home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 140 / Gekkan Dennou Club - 2000.1 Vol. 140 (Japan).7z / Gekkan Dennou Club - 2000.1 Vol. 140 (Japan) (Track 1).bin / tools / dshell / dsh333bs.lzh / sort.c < prev    next >
C/C++ Source or Header  |  1999-12-05  |  68KB  |  3,058 lines

  1. /*
  2.     dshell    v3
  3.  
  4.     テキストファイルを内部バッファへ展開
  5. */
  6.  
  7. #include    "dsh.h"
  8.  
  9.  
  10. static uchar defKinsokuChrs[] =
  11.     "、。」』?!)}〕]〉》】”’,."
  12.     "ぁぃぅぇぉっゃゅょァィゥェォッャュョ";
  13. static uchar *kinsokuChrs;
  14. static uchar Kinw[3];
  15.  
  16.  
  17. #define    nextLine(x) ({ \
  18.     uchar *_p = (x); \
  19.     asm( \
  20. "0:\n" \
  21. "    move.b    (%0)+,d0\n" \
  22. "    beq.s    1f\n" \
  23. "    cmpi.b    #$0a,d0\n" \
  24. "    beq.s    2f\n" \
  25. "    cmpi.b    #$1a,d0\n" \
  26. "    bne.s    0b\n" \
  27. "1:\n" \
  28. "    subq.l    #1,%0\n" \
  29. "2:\n" \
  30.     : "=a"(_p) : "0"(_p) : "d0"); \
  31.     _p; \
  32. })
  33.  
  34. #define    skipNulLine(x) ({ \
  35.     uchar *_p = (x), _c; \
  36.     while ((_c = *_p++) == '\r' || _c == '\n') \
  37.         ; \
  38.     _p - 1; \
  39. }) \
  40.  
  41. #define    skipBlank(x) ({ \
  42.     uchar *_p = (x), _c; \
  43.     while ((_c = *_p++) == '\x20' || _c == '\t') \
  44.         ; \
  45.     _p - 1; \
  46. }) \
  47.  
  48. #define    stpcpy(p, q) ({ \
  49.     uchar *_p = (p); \
  50.     const uchar *_q = (q); \
  51.     while (*_p++ = *_q++) \
  52.         ; \
  53.     _p - 1; \
  54. }) \
  55.  
  56.  
  57. /*
  58.     書式指定
  59. */
  60. typedef struct form {
  61.     struct form *last;
  62.     short width;            // 字詰め幅
  63.     short lmargin;            // 左余白
  64.     short indent;            // インデント
  65.     short lspace;            // 行ごとに挿入する空行の数
  66.     short tabWidth;            // TAB 幅 (特に 0...8桁ごと)
  67.     short boxMargin;        // %box 内の左右マージン
  68.     short cutMargin;        // %CUT 回り込み時のマージン
  69.     uchar eolChr;            // 行末を表す文字
  70.     uchar ctrlChr;            // コマンド先頭文字
  71.     uchar closeChr;            // コマンド閉じ
  72.     uchar closeChr2;        // \n を %V%W の終端と認識するなら \n, でなければ \0
  73.     uchar escChr;            // エスケープ文字
  74.     uchar breakChr;            // 論理行末
  75.     uchar wrapFlag;            // 字詰めの有無
  76.     uchar blockAlignMode;    // 現ブロックの行揃えモード
  77.     signed char fillMode;    // 追い込みの有無とモード (0...なし, >0...文字単位, <0...語単位)
  78.     signed char fillModeDef;    // 追い込み ON 時のモード
  79.     uchar refChr;            // 文字列置換先頭文字
  80. } FORM;
  81.  
  82. static const FORM formInit = {
  83.     NULL,     // last
  84.     0,        // width
  85.     0,        // lmargin
  86.     0,        // indent
  87.     1 - 1,    // lspace
  88.     8,        // tabWidth
  89.     2,        // boxMargin
  90.     2,        // cutMargin
  91.     '\n',    // eolChr
  92.     '%',    // ctrlChr
  93.     '\x18',    // closeChr
  94.     '\n',    // closeChr2
  95.     '\0',    // escChr
  96.     '/',    // breakChr
  97.     TRUE,    // wrapFlag
  98.     0,        // blockAlignMode
  99.     0,        // fillMode
  100.     -1,        // fillModeDef
  101.     0,        // refChr
  102. };
  103.  
  104. #define    Width        (f->width)
  105. #define    Lmargin        (f->lmargin)
  106. #define    Indent        (f->indent)
  107. #define    Lspace        (f->lspace)
  108. #define    TabWidth    (f->tabWidth)
  109. #define    BoxMargin    (f->boxMargin)
  110. #define    CutMargin    (f->cutMargin)
  111. #define    EolChr        (f->eolChr)
  112. #define    CtrlChr        (f->ctrlChr)
  113. #define    CloseChr    (f->closeChr)
  114. #define    CloseChr2    (f->closeChr2)
  115. #define    EscChr    (f->escChr)
  116. #define    BreakChr    (f->breakChr)
  117. #define    WrapFlag    (f->wrapFlag)
  118. #define    BlockAlignMode    (f->blockAlignMode)
  119. #define    FillMode    (f->fillMode)
  120. #define    FillModeDef    (f->fillModeDef)
  121. #define    RefChr        (f->refChr)
  122.  
  123. /*
  124.     書式指定コマンド
  125. */
  126. enum {
  127.     RETRY_CMD,
  128.  
  129.     RESET_CMD,
  130.     WIDTH_CMD,
  131.     LMARGIN_CMD,
  132.     INDENT_CMD,
  133.     TINDENT_CMD,
  134.     LSPACE_CMD,
  135.     TAB_CMD,
  136.     WRAP_CMD,
  137.     FILL_CMD,
  138.     WORDWRAP_CMD,
  139.     ALIGN_CMD,
  140.     SPACE_CMD,
  141.     HRULE_CMD,
  142.     BOX_CMD,
  143.     ENDBOX_CMD,
  144.     BOXMARGIN_CMD,
  145.     CUTMARGIN_CMD,
  146.     CUTFLUSH_CMD,
  147.     CUT_CMD,
  148.  
  149.     CTRLCHAR_CMD,
  150.     ESCCHAR_CMD,
  151.     BREAKCHAR_CMD,
  152.     SEPCHAR_CMD,
  153.     REFCHAR_CMD,
  154.     HANGCHAR_CMD,
  155.  
  156.     SET_CMD,
  157.     INC_CMD,
  158.     CONST_CMD,
  159.  
  160.     FONT_CMD,
  161.     ENDFONT_CMD,
  162.  
  163.     TEXTCOLOR_CMD,
  164.     BGCOLOR_CMD,
  165.     BGCUT_CMD,
  166.  
  167.     PUSH_CMD,
  168.     POP_CMD,
  169.     MACRO_CMD,
  170.     IF_CMD,
  171.     ELIF_CMD,
  172.     ELSE_CMD,
  173.     ENDIF_CMD,
  174.     INCLUDE_CMD,
  175.     END_CMD,
  176.  
  177.     MENU_CMD,
  178.     LABEL_CMD,
  179.  
  180.     NCMDS,
  181. };
  182.  
  183. #define    v3_31    1
  184. #define    v3_32    2
  185. #define    v3_33    3
  186.  
  187. #define    cfBREAK        0x01    // 強制 BREAK
  188. #define    cfNBREAK    0x00
  189.  
  190. static const struct {
  191.     uchar version;
  192.     uchar flag;
  193.     uchar *name;
  194. } commandTable[] = {
  195.     { 0, 0, NULL, },
  196.     { v3_31, cfBREAK, "reset", },
  197.     { v3_31, cfBREAK, "width", },
  198.     { v3_31, cfBREAK, "left-margin", },
  199.     { v3_31, cfBREAK, "indent", },
  200.     { v3_31, cfBREAK, "temp-indent", },
  201.     { v3_31, cfBREAK, "line-space", },
  202.     { v3_31, cfBREAK, "tab-width", },
  203.     { v3_31, cfBREAK, "wrap", },
  204.     { v3_31, cfBREAK, "fill", },
  205.     { v3_31, cfBREAK, "word-wrap", },
  206.     { v3_31, cfBREAK, "align", },
  207.     { v3_31, cfNBREAK, "space", },
  208.     { v3_31, cfBREAK, "h-rule", },
  209.     { v3_32, cfBREAK, "box", },
  210.     { v3_32, cfBREAK, "endbox", },
  211.     { v3_32, cfBREAK, "box-margin", },
  212.     { v3_32, cfBREAK, "cut-margin", },
  213.     { v3_32, cfNBREAK, "cut-flush", },
  214.     { v3_32, cfNBREAK, "cut", },
  215.  
  216.     { v3_31, cfBREAK, "ctrl-char", },
  217.     { v3_31, cfBREAK, "esc-char", },
  218.     { v3_31, cfBREAK, "break-char", },
  219.     { v3_31, cfBREAK, "sep-char", },
  220.     { v3_32, cfBREAK, "ref-char", },
  221.     { v3_31, cfBREAK, "hang-char", },
  222.  
  223.     { v3_32, cfNBREAK, "set", },
  224.     { v3_32, cfNBREAK, "inc", },
  225.     { v3_32, cfNBREAK, "const", },
  226.  
  227.     { v3_32, cfNBREAK, "font", },
  228.     { v3_32, cfNBREAK, "endfont", },
  229.  
  230.     { v3_31, cfBREAK, "text-color", },
  231.     { v3_31, cfBREAK, "bg-color", },
  232.     { v3_31, cfBREAK, "bg-cut", },
  233.  
  234.     { v3_31, cfBREAK, "push", },
  235.     { v3_31, cfBREAK, "pop", },
  236.     { v3_31, cfBREAK, "macro", },
  237.     { v3_32, cfNBREAK, "if", },
  238.     { v3_32, cfNBREAK, "elif", },
  239.     { v3_32, cfNBREAK, "else", },
  240.     { v3_32, cfNBREAK, "endif", },
  241.     { v3_32, cfNBREAK, "include", },
  242.     { v3_31, cfBREAK, "end", },
  243.  
  244.     { v3_33, cfBREAK, "menu", },
  245.     { v3_33, cfBREAK, "label", },
  246. };
  247.  
  248. /*
  249.     マクロ/変数定義
  250. */
  251. typedef struct macro {
  252.     struct macro *next;
  253.     uchar *contents;
  254.     uchar name[0];
  255. } MACRO, VAR;
  256.  
  257. static VAR *varListHead = NULL;
  258.  
  259. typedef struct args {
  260.     struct args *prev;
  261.     VAR *arg[10];
  262. } ARGS;
  263.  
  264. static ARGS *macroArgs;
  265.  
  266. #define    TEXTSTACK_MAX    32    // マクロネスト最大
  267.  
  268. typedef struct {
  269.     uchar *text;
  270.     char flag;
  271. } TEXTSTACK;
  272.  
  273. static TEXTSTACK textStack[TEXTSTACK_MAX + 2], *tsp;
  274. enum {
  275.     inCONST = 0x80,        // &~; の処理中
  276.     inMACRO = 0x01,        // 引数付きマクロの処理中
  277.     inMACRO_NA = 0x02,    // 引数無しマクロの処理中
  278.     inINCLUDE = 0x04,    // %include の処理中
  279. };
  280.  
  281. static int getCommand(uchar *, uchar);
  282. static short getNum(uchar *, short);
  283. static short getNum2(uchar *, short, short, short);
  284. static ushort getRGB(uchar *, ushort);
  285. static uchar getEscSeq(uchar *);
  286. static uchar *getMacro(MACRO *, uchar *, uchar);
  287. static uchar *getIndentStr(uchar *, short);
  288. static uchar *getSysVar(uchar *);
  289. static uchar *getHRule(uchar *, uchar *, short);
  290.  
  291. static uchar refVar(uchar *, const FORM *f);
  292. static VAR *getVar(const uchar *);
  293. static int setVar(const uchar *, const uchar *);
  294. static int incVar(const uchar *);
  295. static int setSysVar(const uchar *, const uchar *);
  296. static uchar *expandCommand(uchar *, uchar *, const FORM *, uchar);
  297. static uchar *expandMacroArg(ARGS *, uchar *, uchar *, const FORM *);
  298. static void freeMacroArg(void);
  299. static int skipIfBlock(const uchar *, uchar, uchar);
  300.  
  301. static int sort_job24(uchar *, uchar *, short, short, const FORM *, uchar *);
  302. static int sort_job12(uchar *, uchar *, short, short, const FORM *, uchar *);
  303. static int sort_job_12_24(uchar *, uchar *, short, short, const FORM *, uchar *, uchar, uchar);
  304. static int getTypeLine(uchar *, uchar *, uchar *, const FORM *);
  305. static int getMenuLine(uchar *, uchar *, uchar *, const FORM *);
  306. static uchar *envSubst(uchar *, uchar *, const FORM *);
  307. static uchar **moveLhp(uchar **, uchar **, int);
  308. static int align(uchar *, uchar *, short, short, uchar);
  309. static short adjustColumn(short, uchar);
  310. static uchar *insertCut(uchar *, short, uchar, uchar, uchar);
  311. static uchar *setColor(uchar *, uchar);
  312.  
  313. extern int evalCond(uchar *);
  314.  
  315. /*
  316.     文字幅等の調整
  317.  
  318.     ptr    修正後のポインタ(表示用に整理し終えたテキスト)
  319.     lhp0    修正前のポインタ(丸読みした状態のテキスト)
  320.         =行ポインタ仮テーブル先頭アドレス(尻尾から)
  321.     fname    ファイル名
  322.     filesize    ファイルサイズ
  323.     noCtrlFlag    非0...制御文字列無効
  324.  
  325.     整理後のテキスト+行ポインタテーブル末尾を返す
  326.     エラーなら NULL
  327. */
  328. static uchar *PTR, *PTR2;
  329. static uchar version;
  330.  
  331. void *
  332. sort(uchar *ptr, uchar **lhp0, uchar *fname, int filesize, uchar noCtrlFlag, void *menuId)
  333. {
  334. #define    LINENO    (lhp0 - tlhp)
  335.     short column;
  336.     uchar **tlhp;    /* 行ポインタ仮テーブル先頭へのポインタ */
  337.     uchar c = '\n';
  338.     uchar *ptr2, *optr2, *lineHead, *wordHead;
  339.     uchar *alignPtr = NULL;
  340.     uchar *indentPtr = NULL;
  341.     short maxColumn;        // 現処理行の字詰め幅
  342.     short alignColumn = 0;
  343.     uchar ctrlChr;
  344.     uchar alignMode;        // 現処理行の行揃えモード
  345.     uchar tempCloseChr;
  346.     uchar bolFlag = TRUE;
  347.     uchar bolFlag2;
  348.     signed char fontSize = 0;    // 現在のフォントサイズ (0...16,1...24,-1...12)
  349.     FORM form, *f = &form;
  350.  
  351.     short defWidth = -1;
  352.     short defLmargin = -1;
  353.     short defLspace = -1 - 1;
  354.     short defTabWidth = -1;
  355.     short defBoxMargin = -1;
  356.     short defCutMargin = -1;
  357.     short tempIndent = -128;
  358.     short lineSpace, leftMargin;
  359.     MACRO *macroListHead = NULL;
  360.     uchar boxStr[20];
  361.     uchar endBoxChars[6+1];
  362.     uchar *boxPtr = NULL;
  363. #define    FONTHIS_MAX    32
  364.     uchar fontHis[FONTHIS_MAX + 1], *fontP;
  365.  
  366.     /* cut ↓ */
  367.     int cutNo = -2;
  368.     uchar cutLineNo = 0;
  369.     uchar cutLineNoMax = 0;
  370.     short cutWidth = 0;
  371.     struct NAMECKBUF docPath;
  372.     uchar cutID[5 + 1];
  373.     signed char cutAlignMode = 0;
  374.     signed char cutBottomSpace = FALSE;
  375.     short cutColumn = 0;
  376.     uchar cutColor = 3;
  377.  
  378.     NAMECK(fname, &docPath);    // '+'オプション時用のパスを得る
  379.     /* cut ↑ */
  380.  
  381.     *f = formInit;
  382.     Width = CWIDTH - 2;
  383.     kinsokuChrs = defKinsokuChrs;
  384.     optr2 = ptr2 = (uchar *)lhp0;    // ベタテキスト先頭
  385.     tlhp = lhp0;
  386.     tsp = textStack + TEXTSTACK_MAX + 1;
  387.     tsp->text = NULL;
  388.     tsp->flag = 0;
  389.     curColor = 3;    // 表示色
  390.     fontP = fontHis;
  391.     *fontP = '\0';
  392.     boxStr[0] = '\0';
  393.  
  394.     version = 0;
  395.     if (noCtrlFlag) {
  396.         CtrlChr = '\0';
  397.     } else {
  398.         uchar *p;
  399.  
  400.         if (strnEqu(ptr2, "%DSHELL", 7)
  401.           && (ptr2[7] == '\x20' || ptr2[7] == '\t')
  402.           && strnEqu(p = skipBlank(ptr2 + 8), "v3.3", 4)
  403.           && (p[4] == '1' || p[4] == '2' || p[4] == '3')) {
  404.             int n;
  405.  
  406.             FillMode--;                    // %fill on, %word-wrap on
  407.             EolChr = BreakChr;            //
  408.             CloseChr2 = '\0';            // %V%W は LF で閉じない
  409.             n = dinstr(defKinsokuChrs, "ぁ");
  410.             if (--n > 0) {
  411.                 defKinsokuChrs[n] = '\0';    //“小さなかな”を行頭禁則対象から外す
  412.                 if ((kinsokuChrs = strdup(defKinsokuChrs)) == NULL)
  413.                     goto HEAP_ERROR;
  414.                 defKinsokuChrs[n] = (uchar)((L'ぁ') >> 8);
  415.             }
  416.             version = v3_31;
  417.             if (p[4] >= '2') {
  418.                 version++;        // v3.32 では
  419.                 EscChr = '\\';    //    %esc-char \ (←う、// 以降でも行末に \ があると行接続が効いちゃうのね...)
  420.                 CloseChr = ';';    //    %sep-char ;
  421.                 RefChr = '&';    //    %ref-char &
  422.                 if (p[4] >= '3')
  423.                     version++;
  424.             }
  425.             ptr2 = nextLine(ptr2);
  426.         }
  427.     }
  428.  
  429.     /*
  430.     !    一番でかいループ
  431.     */
  432.     for (;;) {        /* 各行処理のループ */
  433.  
  434.         /*
  435.             作業進度スケール
  436.         */
  437.         if (filesize > 4*1024 && tsp->flag == 0) {
  438.             short i, j;
  439.             short tbf[10];
  440.             static short oldj = -1;
  441.  
  442.             j = (ptr2 - optr2) * 10 / filesize;
  443.             if (j != oldj) {
  444.                 for (i = 0; i < j; i++) {
  445.                     tbf[i] = L'■';
  446.                 }
  447.                 for (; i < 9; i++) {
  448.                     tbf[i] = L'□';
  449.                 }
  450.                 tbf[9] = 0;
  451.                 w_mes(2, (char *)tbf);
  452.                 oldj = j;
  453.             }
  454.         }
  455.  
  456.         p_time(0);    /* 時計の時間表示 */
  457.  
  458.         if ((void *)ptr > (void *)tlhp)
  459.             goto ERROR;
  460.         *--tlhp = ptr;
  461.  
  462.         ctrlChr = CtrlChr;
  463. LINE_RETRY:
  464.         if (EolChr != '\n')
  465.             ptr2 = skipNulLine(ptr2);
  466.         column = 0;
  467.         leftMargin = Lmargin;
  468.         maxColumn = Width + Lmargin;
  469.         if (boxStr[0] != '\0') {
  470.             short n = boxStr[2] - NUM_BIAS + 2;
  471.             maxColumn = (boxStr[6] - NUM_BIAS) + n - BoxMargin;
  472.             n += BoxMargin;
  473.             if (n > leftMargin)
  474.                 leftMargin = n;
  475.         }
  476.         if (cutAlignMode < 0 || cutBottomSpace < 0) {
  477.             if (cutColumn >= leftMargin)
  478.                 leftMargin = cutColumn + cutWidth + CutMargin;
  479.         }
  480.         if (cutAlignMode > 0 || cutBottomSpace > 0) {
  481.             if (cutColumn < maxColumn)
  482.                 maxColumn = cutColumn - CutMargin;
  483.         }
  484.         cutBottomSpace = 0;
  485.         lineSpace = Lspace;
  486.         alignMode = BlockAlignMode;
  487.         if (!WrapFlag)
  488.             maxColumn = CWIDTH;
  489.         tempCloseChr = EolChr;
  490.         bolFlag2 = TRUE;
  491.         if (bolFlag) {
  492.             if (*ptr2 == (uchar)(L'━' >> 8) && *(ptr2 + 1) == (uchar)(L'━')) {
  493.                 *ptr++ = CTRL_CHAR;
  494.                 *ptr++ = HR_CHAR;
  495.             } else if (ctrlChr != '\0') {
  496.                 if (*ptr2 == '\x18' && FillMode == 0) {
  497.                     /*
  498.                         行頭が^Xの時、改行があるかテキストが終るまで強制的に1行に表示する。
  499.                         (エラーチェックなど一切しないので、使用の際は注意のこと)
  500.                     */
  501.                     ptr2++;
  502.                     maxColumn = SHRT_MAX;    // 十分大きな値
  503.                     ctrlChr = '\0';
  504.                 } else {
  505.                     /*
  506.                         行頭の'◎'
  507.                     */
  508.                     if (*ptr2 == (uchar)(L'◎' >> 8) && *(ptr2 + 1) == (uchar)(L'◎')) {
  509.                         *ptr++ = CTRL_CHAR;
  510.                         *ptr++ = DUMMY_CHAR;    // 仮にダミーの内部コード
  511.                         ptr2 += 2;
  512.                         column += 2;
  513.                         bolFlag2 = FALSE;
  514.                     }
  515.                     /*
  516.                         行頭の ^[[m (埋め込みのブレイクポイント)
  517.                     */
  518.                     if (*ptr2 == '\x1b' && *(ptr2 + 1) == '[' && *(ptr2 + 2) == 'm') {
  519.                         *ptr++ = *ptr2++;
  520.                         *ptr++ = *ptr2++;
  521.                         *ptr++ = *ptr2++;
  522.                         curColor = 3;
  523.                     }
  524.                 }
  525.             }
  526.         }
  527.  
  528.         /*
  529.             前行のフォントを引き継ぐ
  530.         */
  531.         if (fontHis[0] != 0) {
  532.             *ptr++ = CTRL_CHAR;
  533.             *ptr++ = FONT_CHAR;
  534.             ptr = stpcpy(ptr, fontHis);
  535.             *ptr++ = NORM_CHAR;
  536.         }
  537.  
  538.         /*
  539.             %box
  540.         */
  541.         if (boxStr[0] != '\0') {
  542.             boxPtr = ptr;
  543.             ptr = stpcpy(ptr, boxStr);
  544.         }
  545.  
  546.         /*
  547.             インデント
  548.         */
  549.         indentPtr = ptr;
  550.         alignPtr = NULL;
  551.         if (column == 0) {
  552.             switch (alignMode) {
  553.             case '=':
  554.             case '>':
  555.                 column = alignColumn = leftMargin;
  556.                 *ptr++ = '\x1b';
  557.                 *ptr++ = '[';
  558.                 *ptr++ = (column / 10) + '0';
  559.                 *ptr++ = (column % 10) + '0';
  560.                 *ptr++ = 'C';
  561.                 alignPtr = ptr;
  562.                 break;
  563.             default:
  564.                 if (tempIndent > -128) {
  565.                     column = tempIndent;
  566.                     tempIndent = -128;
  567.                 } else {
  568.                     column = leftMargin + Indent;
  569.                 }
  570.                 ptr = getIndentStr(ptr, column);
  571.                 break;
  572.             }
  573.         }
  574.  
  575.         /*
  576.             前行の文字表示属性を引き継ぐ
  577.         */
  578.         if (curColor != 3)
  579.             ptr = setColor(ptr, curColor);
  580.  
  581.         lineHead = ptr;    // ptr == lineHead の間は空行として認識する
  582.         if (!bolFlag2)
  583.             lineHead = NULL;
  584.  
  585.         /*
  586.             前行のフォントサイズを引き継ぐ
  587.         */
  588. FONTSIZE_RETRY:
  589.         wordHead = ptr2;
  590.         if (fontSize != 0) {
  591.             uchar contFlag = FALSE;
  592.  
  593.             if (fontSize > 0)
  594.                 column = sort_job24(ptr, ptr2, column, maxColumn, f, &contFlag);
  595.             else
  596.                 column = sort_job12(ptr, ptr2, column, maxColumn, f, &contFlag);
  597.             ptr = PTR;
  598.             ptr2 = PTR2;
  599.             if (tsp->flag < 0)
  600.                 ctrlChr = '\0';
  601.             wordHead = ptr2;
  602.             if (contFlag && WrapFlag) {
  603.                 bolFlag = (contFlag > TRUE);
  604.                 goto ENCOUNT_EOL;
  605.             }
  606.             fontSize = 0;
  607.         }
  608.  
  609.         /*
  610.         !    1行内の処理
  611.         */
  612.         while (column < maxColumn) {    /* 一行内処理のループ */
  613. CHAR_RETRY:
  614.             c = *ptr2++;    /* 1バイト読み込み */
  615. CTRL_RETRY:
  616.             if (c == '\0' || c == '\x1a') {
  617.                 c = '\0';
  618.                 if (tsp->text != NULL) {
  619.                     wordHead = ptr2 = tsp->text;
  620.                     if (tsp->flag & inMACRO)
  621.                         freeMacroArg();
  622.                     tsp++;
  623.                     ctrlChr = CtrlChr;
  624.                     if (ptr != lineHead)
  625.                         continue;
  626.                     ptr = *tlhp;
  627.                     goto LINE_RETRY;
  628.                 }
  629.                 if (ptr != lineHead) {
  630.                     ptr2--;
  631.                     bolFlag = TRUE;
  632.                     goto ENCOUNT_EOL;
  633.                 }
  634.                 ptr = *tlhp++;
  635.                 goto ENCOUNT_EOF;
  636.             } else if (c == EolChr) {
  637.                 bolFlag = TRUE;
  638.                 goto ENCOUNT_EOL;
  639.             } else if (c == tempCloseChr) {
  640.                 if (alignPtr >= *tlhp) {
  641.                     column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
  642.                     ptr = PTR;
  643.                     alignPtr = NULL;
  644.                 }
  645.                 tempCloseChr = EolChr;
  646.                 alignMode = BlockAlignMode;
  647.                 if (alignMode) {
  648.                     if (column > 0)
  649.                         *ptr++ = '\r';
  650.                     *ptr++ = '\x1b';
  651.                     *ptr++ = '[';
  652.                     *ptr++ = (column / 10) + '0';
  653.                     *ptr++ = (column % 10) + '0';
  654.                     *ptr++ = 'C';
  655.                     alignPtr = ptr;
  656.                     alignColumn = column;
  657.                 }
  658.                 continue;
  659.             } else if (iscntrl(c)) {
  660.                 switch (c) {
  661.                 case '\t':
  662.                     if (TabWidth == 8) {
  663.                         *ptr++ = c;
  664.                         column += 8;
  665.                         column &= -8;
  666.                     } else {
  667.                         short n;
  668.  
  669.                         n = column + TabWidth;
  670.                         n -= (n % TabWidth) + column;
  671.                         while (--n >= 0)
  672.                             *ptr++ = '\f';
  673.                     }
  674.                     continue;
  675.                 case '\b':
  676.                     if (column == 0)
  677.                         continue;
  678.                     *ptr++ = c;
  679.                     column--;
  680.                     continue;
  681.                 case '\f':
  682.                     break;
  683.                 case '\x1b':
  684.                     {
  685.                         int i = isEscSeq(ptr2);
  686.                         if (i > 0) {
  687.                             if (ptr2[i - 1] == 'm' && ptr == lineHead)
  688.                                 lineHead += i + 1;
  689.                             *ptr++ = c;
  690.                             while (--i >= 0)
  691.                                 *ptr++ = *ptr2++;
  692.                             if (*(ptr - 1) == 'C' || *(ptr - 1) == 'D')
  693.                                 column = adjustColumn(column, *(ptr - 1) == 'C');
  694.                             wordHead = ptr2;
  695.                         }
  696.                     }
  697.                     continue;
  698.                 case '\n':
  699.                     if (ptr != lineHead && isalnum(*ptr2) && FillMode < 0) {
  700.                         c = '\x20'; // 次行々頭の英数字列と分離
  701.                         break;
  702.                     }
  703.                     continue;
  704.                 default:
  705.                     continue;
  706.                 }
  707.             } else if (c == EscChr) {
  708.                 c = getEscSeq(ptr2);
  709.                 ptr2 = PTR2;
  710.                 if (c == '\r') {
  711.                     if (column > 0) {
  712.                         *ptr++ = c;
  713.                         column = 0;
  714.                     }
  715.                     continue;
  716.                 }
  717.                 if (iscntrl(c))
  718.                     goto CTRL_RETRY;
  719.             } else if (c == ctrlChr) {
  720.             /*
  721.             !    制御文字を呼び出したか?
  722.             */
  723.                 char command;
  724.                 int n;
  725.  
  726.                 if (ptr2[0] == 'V' && ptr2[1] == ctrlChr && ptr2[2] == 'W') {
  727.                 /*
  728.                 !!    24ドット処理
  729.                 */
  730.                     ptr2 += 3;    // skip "V%W"
  731.                     fontSize++;
  732.                     goto FONTSIZE_RETRY;
  733.                 } else if (ptr2[0] == 'v' && ptr2[1] == ctrlChr && ptr2[2] == 'w') {
  734.                 /*
  735.                     12ドット処理
  736.                 */
  737.                     ptr2 += 3;    // skip "v%w"
  738.                     fontSize--;
  739.                     goto FONTSIZE_RETRY;
  740.                 } else if (ptr2[0] == 'C' && ptr2[1] == 'U' && ptr2[2] == 'T') {
  741.                 /*
  742.                 !!    CUT処理
  743.                 */
  744.                     uchar *pbak = ptr2;
  745.                     ptr2 += 3;    // skip "CUT"
  746.                     if (*ptr2 == ':') {        // カットファイル名指定あり
  747.                         uchar *tail = ptr2;        // 次処理位置
  748.                         struct NAMECKBUF cutFname;    // カットファイル名一時格納先
  749.  
  750.                         cutNo = getCutNo(ptr2 + 1, (char *)&docPath, &cutFname, &tail, CloseChr);
  751.                         if (cutNo >= 0 && cut[cutNo].fname == NULL) {
  752.                             /*
  753.                                 カットファイル名を
  754.                                 整理後テキストの途中 (現在処理行の直前) に移動/挿入する
  755.                             */
  756.                             uchar *p, *q;
  757.  
  758.                             q = ptr;
  759.                             n = strlen((char *)&cutFname) + 1;
  760.                             indentPtr += n;
  761.                             alignPtr += n;
  762.                             lineHead += n;
  763.                             ptr += n;
  764.                             p = ptr;
  765.                             n = q - *tlhp;
  766.                             while (--n >= 0)
  767.                                 *--p = *--q;
  768.                             cut[cutNo].fname = strcpy(q, (char *)&cutFname);
  769.                             *tlhp = p;
  770.                         }
  771.                         ptr2 = tail;
  772.                         if (cutNo >= 0) {
  773.                             if (cut[cutNo].type < 0) {
  774.                                 cutNo = -1;
  775.                             } else {
  776.                                 cutLineNo = NUM_BIAS;
  777.                                 cutLineNoMax = NUM_BIAS + lineCount(cut[cutNo].y);
  778.                                 cutWidth = byteCount(cut[cutNo].x);
  779.                             }
  780.                         }
  781.                     }
  782.  
  783.                     cutAlignMode = 0;
  784.                     if (cutNo >= 0) {    /* "CUT:"より下の行だった時だけCUT表示処理対象とみなす */
  785.                         if (version == 0) {    // 激電の MOKUJI.DOC (他にもあるかも) に見られるゴミスペース対策...
  786.                             uchar *p, cc;
  787.  
  788.                             for (p = ptr2; (cc = *p++) == '\x20' || cc == '\t' || cc == 0x81 && *p++ == 0x40;)
  789.                                 ;
  790.                             p--;
  791.                             if (*p == '\r')
  792.                                 p++;
  793.                             if (*p == '\0' || *p == '\n' || *p == '\x1a')
  794.                                 ptr2 = p;
  795.                         }
  796.                         if ((cut[cutNo].flag & (cutLEFT | cutRIGHT)) && Width < cutWidth + 2) {
  797.                             cut[cutNo].flag &= ~(cutLEFT | cutRIGHT);
  798.                             cut[cutNo].flag |= cutDUP;
  799.                         }
  800.                         if (cut[cutNo].flag & cutLEFT) {
  801.                             cut[cutNo].flag &= ~(cutLEFT | cutRIGHT | cutDUP);
  802.                             cutAlignMode--;
  803.                             cutColumn = Lmargin;
  804.                             if (boxStr[0] != '\0')
  805.                                 cutColumn += 2 + BoxMargin;
  806.                             cutColor = curColor;
  807.                             if (ptr != lineHead)
  808.                                 goto ENCOUNT_EOL;
  809.                             ptr = *tlhp;
  810.                             goto LINE_RETRY;
  811.                         } else if (cut[cutNo].flag & cutRIGHT) {
  812.                             cut[cutNo].flag &= ~(cutLEFT | cutRIGHT | cutDUP);
  813.                             cutAlignMode++;
  814.                             cutColumn = Lmargin + Width - cutWidth;
  815.                             if (boxStr[0] != '\0')
  816.                                 cutColumn -= 2 + BoxMargin;
  817.                             if (cutColumn < 0)
  818.                                 cutColumn = 0;
  819.                             maxColumn = cutColumn - CutMargin;
  820.                             if (maxColumn < 0)
  821.                                 maxColumn = 0;    /////
  822.                             cutColor = curColor;
  823.                             if (ptr != lineHead)
  824.                                 goto ENCOUNT_EOL;
  825.                             continue;
  826.                         }
  827.                         *ptr++ = CTRL_CHAR;
  828.                         *ptr++ = CUT_CHAR;
  829.                         *ptr++ = (cutNo >> 6) + NUM_BIAS;
  830.                         *ptr++ = (cutNo & (64 - 1)) + NUM_BIAS;
  831.                         *ptr++ = cutLineNo++;
  832.                         if (cut[cutNo].flag & cutDUP) {
  833.                             uchar *p = ptr - 5, *q = cutID;
  834.                             *q++ = *p++;
  835.                             *q++ = *p++;
  836.                             *q++ = *p++;
  837.                             *q++ = *p++;
  838.                             *q++ = *p++;
  839.                             *q = '\0';
  840.                         }
  841.                         *ptr++ = column + NUM_BIAS;
  842.                         column += cutWidth;
  843.                         if (cutLineNo >= cutLineNoMax)
  844.                             cutNo = -1;
  845.                         wordHead = ptr2;
  846.                         continue;
  847.                     } else {
  848.                         if (version == 0 && cutNo >= -1 || *(pbak + 3) == ':')
  849.                             continue;
  850.                         ptr2 = pbak;    // 'CUT' の頭に戻して通常文字列扱い
  851.                         if (tsp > textStack + 1)
  852.                             goto CHK_MACRO;
  853.                     }
  854.                 } else if (version > 0 && *(ptr2 - 2) == '\n'
  855.                   && (command = getCommand(ptr2, lineHead == ptr)) >= 0) {
  856.                 /*
  857.                     書式指定コマンド
  858.                 */
  859.                     uchar *pp;
  860.                     static uchar endBoxComStr[] = "\n%endbox";
  861.  
  862.                     if (command == BOX_CMD && boxStr[0] != '\0') {
  863.                         (--tsp)->text = --ptr2;
  864.                         tsp->flag = inMACRO_NA;
  865.                         wordHead = ptr2 = endBoxComStr + 1;
  866.                         *ptr2 = CtrlChr;
  867.                         ptr = *tlhp;
  868.                         tempIndent = boxStr[2] - NUM_BIAS;
  869.                         goto LINE_RETRY;
  870.                     }
  871.                     if (command == RETRY_CMD) {
  872.                         ptr2--;
  873.                         bolFlag = TRUE;
  874.                         goto ENCOUNT_EOL;
  875.                     }
  876.  
  877.                     ptr2 = expandCommand(pp = ptr, PTR2, f, FALSE);
  878.                     switch (command) {
  879.                     case RESET_CMD:
  880.                         if ((Lmargin = defLmargin) < 0)
  881.                             Lmargin = 0;
  882.                         if ((Width = defWidth) < 0)
  883.                             Width = CWIDTH - 2 - Lmargin;
  884.                         Indent = 0;
  885.                         WrapFlag = TRUE;
  886.                         FillMode = FillModeDef;
  887.                         EolChr = BreakChr;
  888.                         BlockAlignMode = 0;
  889.                         if ((Lspace = defLspace) < 0)
  890.                             Lspace = 0;
  891.                         if ((TabWidth = defTabWidth) < 0)
  892.                             TabWidth = 8;
  893.                         if ((BoxMargin = defBoxMargin) < 0)
  894.                             BoxMargin = 0;
  895.                         if ((CutMargin = defCutMargin) < 0)
  896.                             CutMargin = 0;
  897.                         tempIndent = -128;
  898.                         break;
  899.                     case WIDTH_CMD:
  900.                         n = getNum2(pp, Width, defWidth, CWIDTH - 2 - Lmargin);
  901.                         if (n - Indent >= 3 && n + Lmargin <= CWIDTH)
  902.                             Width = n;
  903.                         if (defWidth < 0)
  904.                             defWidth = Width;
  905.                         break;
  906.                     case LMARGIN_CMD:
  907.                         if (*pp == '=')
  908.                             n = (CWIDTH - Width) / 2;
  909.                         else if (*pp == '>')
  910.                             n = CWIDTH - Width;
  911.                         else if (*pp == '<')
  912.                             n = 0;
  913.                         else
  914.                             n = getNum2(pp, Lmargin, defLmargin, 0);
  915.                         if (n >= 0 && n + Width <= CWIDTH)
  916.                             Lmargin = n;
  917.                         if (defLmargin < 0)
  918.                             defLmargin = Lmargin;
  919.                         break;
  920.                     case INDENT_CMD:
  921.                         n = getNum(pp, Indent);
  922.                         if (n < 0)
  923.                             n = 0;
  924.                         if (Width - n >= 3)
  925.                             Indent = n;
  926.                         break;
  927.                     case TINDENT_CMD:
  928.                         n = getNum(pp, Indent);
  929.                         n += Lmargin;
  930.                         if (n >= 0)
  931.                             tempIndent = n;
  932.                         break;
  933.                     case WRAP_CMD:
  934.                         WrapFlag = (strnEqu(pp, "on", 2));
  935.                         break;
  936.                     case FILL_CMD:
  937.                         FillMode = 0;
  938.                         EolChr = '\n';
  939.                         if (strnEqu(pp, "on", 2))
  940.                             FillMode = FillModeDef;
  941.                         if (FillMode)
  942.                             EolChr = BreakChr;
  943.                         break;
  944.                     case WORDWRAP_CMD:
  945.                         FillModeDef = 1;
  946.                         if (strnEqu(pp, "on", 2))
  947.                             FillModeDef--;
  948.                         if (FillMode)
  949.                             FillMode = FillModeDef;
  950.                         break;
  951.                     case ALIGN_CMD:
  952.                         if (strnEqu(pp, "center", 6))
  953.                             BlockAlignMode = '=';
  954.                         else if (strnEqu(pp, "right", 5))
  955.                             BlockAlignMode = '>';
  956.                         else
  957.                             BlockAlignMode = 0;
  958.                         break;
  959.                     case LSPACE_CMD:
  960.                         n = getNum2(pp, Lspace + 1, defLspace + 1, 1);
  961.                         if (n < 1)
  962.                             n = 1;
  963.                         Lspace = n - 1;
  964.                         if (defLspace < 0)
  965.                             defLspace = Lspace;
  966.                         break;
  967.                     case TAB_CMD:
  968.                         n = TabWidth;
  969.                         n = getNum2(pp, n, defTabWidth, 8);
  970.                         if (n < 1)
  971.                             n = 1;
  972.                         TabWidth = n;
  973.                         if (defTabWidth < 0)
  974.                             defTabWidth = TabWidth;
  975.                         break;
  976.                     case SPACE_CMD:
  977.                         n = 1;
  978.                         if (*pp != '\n')
  979.                             n = getNum(pp, 1);
  980.                         if (n < 0)
  981.                             continue;
  982.                         lineSpace = n;
  983.                         if (ptr == lineHead)
  984.                             lineSpace--;
  985.                         bolFlag = TRUE;
  986.                         goto ENCOUNT_EOL;
  987.                     case HRULE_CMD:
  988.                         {
  989.                             uchar *p, *q;
  990.                             int n;
  991.  
  992.                             p = indentPtr;
  993.                             ptr = getIndentStr(p, leftMargin);
  994.                             ptr = getHRule(ptr, pp, maxColumn - leftMargin);
  995.                             if (*p++ == (uchar)(L'━' >> 8) && *p == (uchar)(L'━')) {
  996.                                 n = ptr - *tlhp;
  997.                                 q = ptr;
  998.                                 ptr += 2;
  999.                                 p = ptr;
  1000.                                 while (--n >= 0)
  1001.                                     *--p = *--q;
  1002.                                 *--p = HR_CHAR;
  1003.                                 *--p = CTRL_CHAR;
  1004.                             }
  1005.                             alignPtr = NULL;
  1006.                         }
  1007.                         bolFlag = TRUE;
  1008.                         goto ENCOUNT_EOL;
  1009.                     case BOX_CMD:
  1010.                         if (maxColumn - column >= 6){
  1011.                             uchar buff[20], *p;
  1012.  
  1013.                             p = strcpy(buff, "┌─┐││└─┘");
  1014.                             for (n = 0; n < 8 && iskanji(*pp); n++) {
  1015.                                 *p++ = *pp++;
  1016.                                 *p++ = *pp++;
  1017.                             }
  1018.                             p = boxStr;
  1019.                             *p++ = CTRL_CHAR;
  1020.                             *p++ = BOX_CHAR;
  1021.                             *p++ = leftMargin + NUM_BIAS;
  1022.                             *p++ = (curColor & 3) + NUM_BIAS;
  1023.                             *p++ = buff[6];
  1024.                             *p++ = buff[7];
  1025.                             *p++ = ((maxColumn - leftMargin - 4) & -2) + NUM_BIAS;
  1026.                             *p++ = buff[8];
  1027.                             *p++ = buff[9];
  1028.                             *p = '\0';
  1029.                             strcpy(endBoxChars, buff + 10);
  1030.                             buff[6] = '\0';
  1031.                             ptr = getIndentStr(indentPtr, leftMargin);
  1032.                             ptr = getHRule(ptr, buff, maxColumn - leftMargin);
  1033.                             alignPtr = NULL;
  1034.                             bolFlag = TRUE;
  1035.                             leftMargin += 2;
  1036.                             goto ENCOUNT_EOL;
  1037.                         }
  1038.                         break;
  1039.                     case ENDBOX_CMD:
  1040.                         if (boxStr[0] != '\0') {
  1041.                             boxStr[0] = '\0';
  1042.                             ptr = getIndentStr(boxPtr, boxStr[2] - NUM_BIAS);
  1043.                             ptr = getHRule(ptr, endBoxChars, boxStr[6] - NUM_BIAS + 4);
  1044.                             alignPtr = NULL;
  1045.                             bolFlag = TRUE;
  1046.                             goto ENCOUNT_EOL;
  1047.                         }
  1048.                         break;
  1049.                     case BOXMARGIN_CMD:
  1050.                         n = getNum2(pp, BoxMargin, defBoxMargin, 2);
  1051.                         if (CWIDTH - n - n - 4 > 0)
  1052.                             BoxMargin = n;
  1053.                         if (defBoxMargin < 0)
  1054.                             defBoxMargin = BoxMargin;
  1055.                         break;
  1056.                     case CUTMARGIN_CMD:
  1057.                         n = getNum2(pp, CutMargin, defCutMargin, 2);
  1058.                         if (CWIDTH - n > 3)
  1059.                             CutMargin = n;
  1060.                         if (defCutMargin < 0)
  1061.                             defCutMargin = CutMargin;
  1062.                         break;
  1063.                     case CUTFLUSH_CMD:
  1064.                         if (cutAlignMode != 0 && cutNo >= 0 && cutLineNo < cutLineNoMax - 1) {
  1065.                             lineSpace = cutLineNoMax - cutLineNo - 1 + Lspace;
  1066.                             bolFlag = TRUE;
  1067.                             goto ENCOUNT_EOL;
  1068.                         }
  1069.                         continue;
  1070.                     case CUT_CMD:
  1071.                         {
  1072.                             uchar *qq, cc;
  1073.  
  1074.                             for (qq = pp; (cc = *qq++) > ' ' && cc != CloseChr;)
  1075.                                 ;
  1076.                             (--tsp)->text = ptr2;
  1077.                             tsp->flag = inMACRO_NA;
  1078.                             wordHead = ptr2 = qq + 256;
  1079.                             if ((void *)ptr2 + (qq - pp) > (void *)tlhp)
  1080.                                 goto ERROR;
  1081.                             *--qq = '\0';
  1082.                             qq = stpcpy(ptr2, "%CUT:?-");    // 旧書式に変換
  1083.                             strcpy(qq, pp);
  1084.                             *ptr2 = CtrlChr;
  1085.                         }
  1086.                         continue;
  1087.                     case CTRLCHAR_CMD:
  1088.                         if (!iscntrl(*pp) && !iskanji1(*pp))
  1089.                             CtrlChr = ctrlChr = *pp++;
  1090.                         break;
  1091.                     case BREAKCHAR_CMD:
  1092.                         BreakChr = '\n';
  1093.                         if (!iscntrl(*pp) && !iskanji1(*pp))
  1094.                             BreakChr = *pp++;
  1095.                         if (FillMode)
  1096.                             EolChr = BreakChr;
  1097.                         break;
  1098.                     case ESCCHAR_CMD:
  1099.                         EscChr = '\0';
  1100.                         if (!iscntrl(*pp) && !iskanji1(*pp))
  1101.                             EscChr = *pp++;
  1102.                         break;
  1103.                     case SEPCHAR_CMD:
  1104.                         CloseChr = '\x18';
  1105.                         if (!iscntrl(*pp) && !iskanji1(*pp))
  1106.                             CloseChr = *pp++;
  1107.                         break;
  1108.                     case REFCHAR_CMD:
  1109.                         RefChr = '\0';
  1110.                         if (!iscntrl(*pp) && !iskanji1(*pp))
  1111.                             RefChr = *pp++;
  1112.                         break;
  1113.                     case HANGCHAR_CMD:
  1114.                         if (kinsokuChrs != defKinsokuChrs)
  1115.                             free(kinsokuChrs);
  1116.                         kinsokuChrs = pp;
  1117.                         while (iskanji(*pp))
  1118.                             pp += 2;
  1119.                         {
  1120.                             uchar cc = *pp;
  1121.                             *pp = '\0';
  1122.                             kinsokuChrs = strdup(kinsokuChrs);
  1123.                             *pp = cc;
  1124.                         }
  1125.                         if (kinsokuChrs == NULL)
  1126.                             goto HEAP_ERROR;
  1127.                         break;
  1128.                     case TEXTCOLOR_CMD:
  1129.                         tx_col[3] = getRGB(pp, tx_col[3]);
  1130.                         break;
  1131.                     case BGCOLOR_CMD:
  1132.                         gr_col[0] = getRGB(pp, gr_col[0]);
  1133.                         break;
  1134.                     case BGCUT_CMD:
  1135.                         if (*pp == '-') {
  1136.                             bgCut = NULL;
  1137.                         } else {
  1138.                             if ((pp = strdup(pp)) == NULL)
  1139.                                 goto HEAP_ERROR;
  1140.                             ptr = *tlhp;
  1141.                             n = getCutNo(pp, (char *)&docPath, (struct NAMECKBUF *)ptr, NULL, CloseChr);
  1142.                             free(pp);
  1143.                             if (n >= 0) {
  1144.                                 if (cut[n].fname == NULL) {
  1145.                                     cut[n].fname = ptr;
  1146.                                     while (*ptr++)
  1147.                                         ;
  1148.                                     *tlhp = ptr;
  1149.                                 }
  1150.                                 bgCut = &cut[n];
  1151.                             }
  1152.                         }
  1153.                         break;
  1154.                     case PUSH_CMD:
  1155.                         {
  1156.                             FORM *ff = malloc(sizeof(FORM));
  1157.                             if (ff == NULL)
  1158.                                 goto HEAP_ERROR;
  1159.                             *ff = *f;
  1160.                             ff->last = f;
  1161.                             f = ff;
  1162.                         }
  1163.                         break;
  1164.                     case POP_CMD:
  1165.                         if (f->last != NULL) {
  1166.                             FORM *ff = f;
  1167.                             f = f->last;
  1168.                             free(ff);
  1169.                         }
  1170.                         break;
  1171.                     case MACRO_CMD:
  1172.                         if ((tsp->flag & ~inINCLUDE) == 0) {
  1173.                             uchar *name, *contents, cc;
  1174.                             int l;
  1175.                             MACRO *macP;
  1176.  
  1177.                             name = pp;
  1178.                             while ((cc = *pp++) > '\x20'
  1179.                               && cc != ctrlChr && cc != CloseChr && cc != '(')
  1180.                                 ;
  1181.                             *--pp = '\0';
  1182.                             if ((l = pp - name) == 0 || *ptr2 == '\0' || *ptr2 == '\x1a')
  1183.                                 break;
  1184.                             contents = ptr2;
  1185.                             do {
  1186.                                 ptr2 += strcspn(ptr2, "\n\x1a");
  1187.                                 if (*ptr2 != '\n')
  1188.                                     break;
  1189.                                 ptr2++;                                    
  1190.                             } while (*ptr2 != ctrlChr || !strnEqu(ptr2 + 1, "endm", 4) || *(ptr2 + 5) > '\x20');
  1191.                             macP = malloc(sizeof(MACRO) + (l + 1));
  1192.                             if (macP == NULL)
  1193.                                 goto HEAP_ERROR;
  1194.                             macP->next = macroListHead;
  1195.                             macroListHead = macP;
  1196.                             macP->contents = contents;
  1197.                             strncpy(macP->name, name, l);
  1198.                             macP->name[l] = '\0';
  1199.                             *ptr2++ = '\x1a';
  1200.                             *ptr2++ = '\x1a';
  1201.                             ptr2 = nextLine(ptr2);
  1202. //                            if (EolChr != '\n')
  1203. //                                ptr2 = skipNulLine(ptr2);
  1204.                         }
  1205.                         break;
  1206.                     case SET_CMD:
  1207.                         {
  1208.                             uchar *name = pp, cc;
  1209.  
  1210.                             while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
  1211.                                 ;
  1212.                             *--pp = '\0';
  1213.                             if (pp++ == name || cc != '='
  1214.                               || name[1] == '\0' && isdigit(name[0]))
  1215.                                 break;
  1216.                             if (setVar(name, pp) < 0)
  1217.                                 goto HEAP_ERROR;
  1218.                         }
  1219.                         if (lineHead == ptr)
  1220.                             break;
  1221.                         continue;
  1222.                     case INC_CMD:
  1223.                         {
  1224.                             uchar *name = pp, cc;
  1225.  
  1226.                             while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
  1227.                                 ;
  1228.                             *--pp = '\0';
  1229.                             if (pp != name && (name[1] != '\0' || !isdigit(name[0]))) {
  1230.                                 if (incVar(name) < 0)
  1231.                                     goto HEAP_ERROR;
  1232.                             }
  1233.                         }
  1234.                         if (lineHead == ptr)
  1235.                             break;
  1236.                         continue;
  1237.                     case CONST_CMD:
  1238.                         {
  1239.                             uchar *name = pp, cc;
  1240.  
  1241.                             while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
  1242.                                 ;
  1243.                             *--pp = '\0';
  1244.                             if (pp++ == name || cc != '=')
  1245.                                 break;
  1246.                             if (setSysVar(name, pp) < 0)
  1247.                                 goto HEAP_ERROR;
  1248.                         }
  1249.                         if (lineHead == ptr)
  1250.                             break;
  1251.                         continue;
  1252.                     case FONT_CMD:
  1253.                         if (fontP < fontHis + FONTHIS_MAX) {
  1254.                             int fontNo;
  1255.                             struct NAMECKBUF fontFname;
  1256.  
  1257.                             if ((pp = strdup(pp)) == NULL)
  1258.                                 goto HEAP_ERROR;
  1259.                             fontNo = getFontNo(pp, (char *)&docPath, &fontFname, CloseChr);
  1260.                             free(pp);
  1261.                             if (fontNo >= 0) {
  1262.                                 if (font16[fontNo].fname == NULL) {
  1263.                                     uchar *p, *q;
  1264.  
  1265.                                     q = ptr;
  1266.                                     n = strlen((char *)&fontFname) + 1;
  1267.                                     indentPtr += n;
  1268.                                     alignPtr += n;
  1269.                                     lineHead += n;
  1270.                                     ptr += n;
  1271.                                     p = ptr;
  1272.                                     n = q - *tlhp;
  1273.                                     while (--n >= 0)
  1274.                                         *--p = *--q;
  1275.                                     font16[fontNo].fname = strcpy(q, (char *)&fontFname);
  1276.                                     *tlhp = p;
  1277.                                 }
  1278.                                 if (font16[fontNo].size > 0) {
  1279.                                     *fontP++ = fontNo + NUM_BIAS;
  1280.                                     *fontP = '\0';
  1281.                                     if (ptr > lineHead) {
  1282.                                         *ptr++ = CTRL_CHAR;
  1283.                                         *ptr++ = FONT_CHAR;
  1284.                                         *ptr++ = fontNo + NUM_BIAS;
  1285.                                         *ptr++ = NORM_CHAR;
  1286.                                     }
  1287.                                 }
  1288.                             }
  1289.                         }
  1290.                         if (lineHead == ptr)
  1291.                             break;
  1292.                         continue;
  1293.                     case ENDFONT_CMD:
  1294.                         if (fontHis[0] != '\0') {
  1295.                             *--fontP = '\0';
  1296.                             if (ptr > lineHead) {
  1297.                                 *ptr++ = CTRL_CHAR;
  1298.                                 *ptr++ = EFONT_CHAR;
  1299.                             }
  1300.                         }
  1301.                         if (lineHead == ptr)
  1302.                             break;
  1303.                         continue;
  1304.                     case IF_CMD:
  1305.                         while (evalCond(pp) <= 0) {
  1306.                             if (!skipIfBlock(ptr2, CtrlChr, TRUE)) {
  1307.                                 ptr2 = PTR2;
  1308.                                 if (EolChr != '\n')
  1309.                                     ptr2 = skipNulLine(ptr2);
  1310.                                 break;
  1311.                             }
  1312.                             ptr2 = expandCommand(pp, PTR2, f, FALSE);
  1313.                         }
  1314.                         continue;
  1315.                     case ELIF_CMD:
  1316.                     case ELSE_CMD:
  1317.                         skipIfBlock(ptr2, CtrlChr, FALSE);
  1318.                         ptr2 = PTR2;
  1319.                         if (EolChr != '\n')
  1320.                             ptr2 = skipNulLine(ptr2);
  1321.                         continue;
  1322.                     case ENDIF_CMD:
  1323.                         continue;
  1324.                     case INCLUDE_CMD:
  1325.                         {
  1326.                             FILE *fp;
  1327.                             uchar *fname = pp;
  1328.                             uchar temp[256];
  1329.                             uchar **p1, **p2;
  1330.                             int m;
  1331.  
  1332.                             if (tsp <= textStack + 1) {
  1333. INCLUDE_ERROR:
  1334.                                 for (pp = "*ERROR: include"; *ptr++ = *pp++;)
  1335.                                     ;
  1336.                                 goto ENCOUNT_EOL0;
  1337.                             }
  1338.                             while (*pp++ > '\x20')
  1339.                                 ;
  1340.                             *--pp = '\0';
  1341.                             if (pp - fname == 0 || pp - fname > 90)
  1342.                                 goto INCLUDE_ERROR;
  1343.                             if (*fname == '+') {
  1344.                                 strcpy(temp, (char *)&docPath);
  1345.                                 fname = strcat(temp, fname);
  1346.                             }
  1347.                             fp = fopen(fname, "rb");
  1348.                             if (fp == NULL || (n = dfilelength(fileno(fp))) < 0)
  1349.                                 goto INCLUDE_ERROR;
  1350.                             if (n == 0) {
  1351.                                 fclose(fp);
  1352.                                 break;
  1353.                             }
  1354.                             p1 = ((void *)tlhp) - ((n + 3 + 3) & -4);
  1355.                             if ((uchar *)p1 < ptr)
  1356.                                 goto ERROR;
  1357.                             p2 = tlhp;
  1358.                             m = lhp0 - tlhp;
  1359.                             tlhp = p1;
  1360.                             while (--m >= 0)
  1361.                                 *p1++ = *p2++;
  1362.                             lhp0 = p1;
  1363.                             pp = (uchar *)p1;
  1364.                             *pp++ = '\n';
  1365.                             m = fread(pp, sizeof(char), n, fp);
  1366.                             fclose(fp);
  1367.                             if (m != n)
  1368.                                 goto INCLUDE_ERROR;
  1369.                             *(pp + n) = '\0';
  1370.                             *(pp + n + 1) = '\0';
  1371.                             (--tsp)->text = ptr2;
  1372.                             tsp->flag = inINCLUDE;
  1373.                             ptr2 = pp;
  1374.                             if (EolChr != '\n')
  1375.                                 ptr2 = skipNulLine(ptr2);
  1376.                             wordHead = ptr2;
  1377.                         }
  1378.                         if (ptr != lineHead)
  1379.                             continue;
  1380.                         break;
  1381.                     case END_CMD:
  1382.                         ptr = *tlhp++;
  1383.                         goto ENCOUNT_EOF;
  1384.                     case MENU_CMD:
  1385.                         ptr = *tlhp;
  1386.                         while (*ptr2 != '\0' && *ptr2 != '\x1a') {
  1387.                             if (*ptr2 == ctrlChr
  1388.                               && strnEqu(ptr2 + 1, "endmenu", 7)
  1389.                               && *(ptr2 + 8) <= '\x20') {
  1390.                                 ptr2 = nextLine(ptr2);
  1391.                                 break;
  1392.                             }
  1393.                             if (getMenuLine(ptr, ptr2, (uchar *)tlhp, f) < 0)
  1394.                                 goto ERROR;
  1395.                             if (addMenuItem(menuId, ptr) < 0)
  1396.                                 goto HEAP_ERROR;
  1397.                             ptr = PTR;
  1398.                             ptr2 = PTR2;
  1399.                         }
  1400.                         *tlhp = ptr;
  1401.                         bolFlag = TRUE;
  1402.                         goto LINE_RETRY;
  1403.                     case LABEL_CMD:
  1404.                         ptr = *tlhp;
  1405.                         bolFlag = TRUE;
  1406.                         goto LINE_RETRY;
  1407.                     }
  1408.                     ptr = *tlhp;
  1409.                     goto LINE_RETRY;
  1410.                 } else if (version > 0 && *ptr2 == '-' && *(ptr2 + 1) == '-') {
  1411.                 /*
  1412.                     ブロックコメント (%-- ~ --%)
  1413.                 */
  1414.                     for (;;) {
  1415.                         ptr2 += strcspn(ptr2, "-\x1a");
  1416.                         if (*ptr2 != '-')
  1417.                             break;
  1418.                         if (*++ptr2 == '-'
  1419.                           && (*(ptr2 + 1) == ctrlChr || *(ptr2 + 1) == CloseChr)) {
  1420.                             ptr2 += 2;
  1421.                             break;
  1422.                         }
  1423.                     }
  1424.                     continue;
  1425.                 } else if (version > 0 && *ptr2 == '/' && *(ptr2 + 1) == '/') {
  1426.                 /*
  1427.                     行コメント (%// ~)
  1428.                 */
  1429.                     ptr2 = nextLine(ptr2);
  1430.                     if (EolChr != '\n')
  1431.                         ptr2 = skipNulLine(ptr2);
  1432.                     ptr = *tlhp;
  1433.                     goto LINE_RETRY;
  1434.                 } else if (*ptr2 == *(ptr2 + 1) && strchr("<=>", *ptr2) != NULL) {
  1435.                 /*
  1436.                     一時的な行揃え (%<<, %==, %>>)
  1437.                 */
  1438.                     if (alignPtr >= *tlhp) {
  1439.                         column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
  1440.                         ptr = PTR;
  1441.                         alignPtr = NULL;
  1442.                     }
  1443.                     tempCloseChr = CloseChr;
  1444.                     if (column > 0)
  1445.                         *ptr++ = '\r';
  1446.                     switch (*ptr2) {
  1447.                     case '<':    // 左詰め
  1448.                         ptr2 += 2;
  1449.                         if ((column = leftMargin) > 0)
  1450.                             ptr = getIndentStr(ptr, column);
  1451.                         if (*ptr2 == (uchar)(L'━' >> 8) && *(ptr2 + 1) == (uchar)(L'━')) {
  1452.                             *ptr++ = CTRL_CHAR;
  1453.                             *ptr++ = HR_CHAR;
  1454.                         }
  1455.                         break;
  1456.                     case '=':    // センタリング
  1457.                     case '>':    // 右詰め
  1458.                         alignMode = *ptr2;
  1459.                         ptr2 += 2;
  1460.                         *ptr++ = '\x1b';
  1461.                         *ptr++ = '[';
  1462.                         *ptr++ = (column / 10) + '0';
  1463.                         *ptr++ = (column % 10) + '0';
  1464.                         *ptr++ = 'C';
  1465.                         alignPtr = ptr;
  1466.                         alignColumn = column;
  1467.                         break;
  1468.                     }
  1469.                     continue;
  1470.                 } else if (version > 0) {
  1471.                 /*
  1472.                     ユーザー定義マクロ
  1473.                 */
  1474.                     uchar *p;
  1475. CHK_MACRO:
  1476.                     p = getMacro(macroListHead, ptr2, CloseChr);
  1477.                     ptr2 = PTR2;
  1478.                     if (p == NULL)
  1479.                         continue;
  1480.                     if (tsp <= textStack + 1) {
  1481.                         for (p = "*ERROR: macro"; *ptr++ = *p++;)
  1482.                             ;
  1483.                         goto ENCOUNT_EOL0;
  1484.                     }
  1485.                     if (p != NULL) {
  1486.                         ARGS *ap;
  1487.                         if ((ap = malloc(sizeof(ARGS))) == NULL)
  1488.                             goto HEAP_ERROR;
  1489.                         for (n = 0; n < 10; n++)
  1490.                             ap->arg[n] = NULL;
  1491.                         if (*ptr2 == '(' && version >= v3_32) {
  1492.                             ptr2 = expandMacroArg(ap, ptr, ptr2 + 1, f);
  1493.                             if (ptr2 == NULL)
  1494.                                 goto HEAP_ERROR;
  1495.                         }
  1496.                         ap->prev = macroArgs;
  1497.                         macroArgs = ap;
  1498.                         if (*ptr2 == CloseChr)
  1499.                             ptr2++;
  1500.                         if (EolChr != '\n')
  1501.                             ptr2 = skipNulLine(ptr2);
  1502.                         (--tsp)->text = ptr2;
  1503.                         tsp->flag = inMACRO;
  1504.                         ptr2 = p;
  1505.                         if (EolChr != '\n')
  1506.                             ptr2 = skipNulLine(ptr2);
  1507.                         wordHead = ptr2;
  1508.                         if (ptr != lineHead)
  1509.                             continue;
  1510.                         ptr = *tlhp;
  1511.                         goto LINE_RETRY;
  1512.                     }
  1513.                 }
  1514.             } else if (c == RefChr && ctrlChr != '\0' && tsp > textStack + 1) {
  1515.                 c = refVar(ptr2, f);
  1516.                 ptr2 = PTR2;
  1517.                 if (c == 0) {
  1518.                     ctrlChr = '\0';
  1519.                     wordHead = ptr2;
  1520.                     continue;
  1521.                 }
  1522.             } else if (c == 'T' && ctrlChr != '\0'
  1523.               && (strnEqu(ptr2, "YPE=", 4) || strnEqu(ptr2, "ype=", 4))
  1524.               && (isalpha(ptr2[4]) && isalpha(ptr2[5]) && isalpha(ptr2[6]))
  1525.               && (ptr2[7] == ':' || ptr2[7] == ',' || ptr2[7] == ';')
  1526. //              && ptr2[8] >= '\x20') {
  1527.               ) {
  1528.                 uchar *head = *tlhp, *p;
  1529.  
  1530.                 if ((*head == CTRL_CHAR || tlhp < lhp0 && *(head = *(tlhp + 1)) == CTRL_CHAR)
  1531.                   && *(head + 1) == DUMMY_CHAR) {
  1532.                     *(head + 1) = EXEC_CHAR;
  1533.                     if (*ptr2 == 'y') {
  1534.                         /*
  1535.                             'Type='
  1536.                         */
  1537.                         ptr2 += 4;    // skip 'ype='
  1538.                         for (p = ptr; --ptr >= *tlhp;) {
  1539.                             if (*ptr != '\x20' || *ptr != '\t' || *ptr != '\f')
  1540.                                 break;
  1541.                         }
  1542.                         ptr++;
  1543.                         *ptr++ = CTRL_CHAR;
  1544.                         *ptr++ = NULTYPE_CHAR;
  1545.                         while ((c = *ptr2++) != '\0' && c != '\n' && c != '\x1a') {
  1546.                             if (c == '\r')
  1547.                                 continue;
  1548.                             if (c == RefChr) {
  1549.                                 if (ptr + 256 > (uchar *)tlhp)
  1550.                                     goto ERROR;
  1551.                                 ptr = envSubst(ptr, ptr2, f);
  1552.                                 ptr2 = PTR2;
  1553.                                 continue;
  1554.                             }
  1555.                             *ptr++ = c;
  1556.                             if (iskanji1(c))
  1557.                                 *ptr++ = *ptr2++;
  1558.                         }
  1559.                         *ptr++ = '\0';
  1560.                         bolFlag = TRUE;
  1561.                         goto ENCOUNT_EOL0;
  1562.                     } else {
  1563.                         /*
  1564.                             'TYPE=~' を '<~' に置き換えた上で右揃えする
  1565.                         */
  1566.                         int n, k;
  1567.                         short m;
  1568.                         uchar *temp;
  1569.  
  1570.                         k = CWIDTH - 2;
  1571.                         if (Width + Lmargin > k)
  1572.                             k = Width + Lmargin;
  1573.                         ptr2 += 4;    // skip 'YPE='
  1574.                         for (p = ptr; --ptr >= *tlhp;) {    // 先行する空白を取り除く
  1575.                             if (*ptr == '\x20' || *ptr == '\f') {
  1576.                                 column--;
  1577.                                 continue;
  1578.                             }
  1579.                             if (*ptr == '\t' && *(ptr - 1) == '\t') {    // TAB が1個残るのは仕様
  1580.                                 column -= 8;
  1581.                                 continue;
  1582.                             }
  1583.                             break;
  1584.                         }
  1585.                         ptr++;
  1586.                         temp = ptr + 32;
  1587.                         n = getTypeLine(temp, ptr2, (uchar *)tlhp, f) + 2;    // +2...'<' と '>' の分
  1588.                         ptr2 = PTR2;
  1589.                         if (n < 0)
  1590.                             goto ERROR;
  1591.                         if (n > 128)
  1592.                             goto TOO_LONG_TYPE;
  1593.                         if ((n < k || column + n > 128)
  1594.                           && column + n > k && head == *tlhp) {
  1595.                             *ptr++ = '\0';
  1596.                             *--tlhp = ptr;
  1597.                             if ((void *)ptr > (void *)tlhp)
  1598.                                 goto ERROR;
  1599.                             column = 0;
  1600.                         }
  1601.                         if (column + n > 128)
  1602.                             goto TOO_LONG_TYPE;
  1603.                         m = k - n - column;
  1604.                         if (m > 0) {
  1605.                             if (m >= 4) {
  1606.                                 *ptr++ = '\x1b';
  1607.                                 *ptr++ = '[';
  1608.                                 if (m >= 10) {    // m < 100 を仮定
  1609.                                     *ptr++ = (m / 10) + '0';
  1610.                                     m %= 10;
  1611.                                 }
  1612.                                 *ptr++ = m + '0';
  1613.                                 *ptr++ = 'C';
  1614.                             } else {
  1615.                                 while (--m >= 0)
  1616.                                     *ptr++ = '\f';
  1617.                             }
  1618.                         }
  1619.                         *ptr++ = CTRL_CHAR;
  1620.                         *ptr++ = TYPE_CHAR;
  1621.                         while (*ptr++ = *temp++)
  1622.                             ;
  1623.                         bolFlag = TRUE;
  1624.                         goto ENCOUNT_EOL0;
  1625.  
  1626. TOO_LONG_TYPE:
  1627.                         *head++ = (uchar)(L'◎' >> 8);
  1628.                         *head = (uchar)(L'◎');
  1629.                         for (p = "*ERROR: TYPE"; *ptr++ = *p++;)
  1630.                             ;
  1631.                         bolFlag = TRUE;
  1632.                         goto ENCOUNT_EOL0;
  1633.                     }
  1634.                 }
  1635.             }
  1636.             /*
  1637.             !    制御文字処理は取り敢えずここまで
  1638.             */
  1639.  
  1640.             if (column == (maxColumn - 1) && iskanji(c)) {
  1641.                 --ptr2;
  1642.                 break;
  1643.             }
  1644.             *ptr++ = c;
  1645.             column++;
  1646.  
  1647.             /* 全角文字処理 ↓ */
  1648.             if (iskanji1(c)) {
  1649.                 if (*ptr++ = *ptr2++) {
  1650.                     if (iskanji(c))
  1651.                         column++;
  1652.                 } else {    // 第2バイトが00の文字は EOF 扱い
  1653.                     ptr -= 2;
  1654.                     column--;
  1655.                     c = '\0';
  1656.                     goto CTRL_RETRY;
  1657.                 }
  1658.             }
  1659.             /* 全角文字処理 ↑ */
  1660.  
  1661.         }
  1662.         /*
  1663.         !    一行の処理は取り敢えずここまで
  1664.         */
  1665.  
  1666.  
  1667.         bolFlag = FALSE;
  1668.         /*
  1669.             未処理のままの中央揃え/右揃えの後始末
  1670.         */
  1671.         if (alignPtr >= *tlhp) {
  1672.             column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
  1673.             ptr = PTR;
  1674.             alignPtr = NULL;
  1675.         }
  1676.  
  1677.         /*
  1678.             語単位の追い込み
  1679.         */
  1680.         if (FillMode < 0 && isalnum(c) && (isalnum(*ptr2) || *ptr2 == '.' || *ptr2 == ',' || *ptr2 == ';')) {
  1681.             uchar *p = ptr2;
  1682.             short n;
  1683.  
  1684.             while (p >= wordHead) {
  1685.                 uchar cc;
  1686.                 cc = *--p;
  1687.                 if (!isalnum(cc)) {
  1688.                     p++;
  1689.                     break;
  1690.                 }
  1691.             }
  1692.             if (p > wordHead) {
  1693.                 n = ptr2 - p;
  1694.                 if (n <= Width) {
  1695.                     column -= n;
  1696.                     ptr -= n;
  1697.                     ptr2 -= n;
  1698.                 }
  1699.             }
  1700.         }
  1701.         /*
  1702.         !    禁足処理(めんどくさいからやめたい)
  1703.         */
  1704.         if (column >= maxColumn - 1 && column <= maxColumn && iskanji(*ptr2)) {
  1705.             Kinw[0] = ptr2[0];
  1706.             Kinw[1] = ptr2[1];
  1707.             if (dinstr(kinsokuChrs, Kinw)) {
  1708.                 *ptr++ = *ptr2++;
  1709.                 *ptr++ = *ptr2++;
  1710.                 column += 2;
  1711.             }
  1712.         }
  1713.         /*
  1714.             行末の制御文字
  1715.         */
  1716.         for (;;) {
  1717.             c = *ptr2++;
  1718.  
  1719.             if (c == '\0' || c == EolChr || c == '\x1a') {
  1720.                 bolFlag = (c == EolChr);
  1721.                 break;
  1722.             } else if (c == '\x1b') {
  1723.                 int i = isEscSeq(ptr2);
  1724.                 if (i > 0) {
  1725.                     *ptr++ = c;
  1726.                     while (--i >= 0)
  1727.                         *ptr++ = *ptr2++;
  1728.                     if (*(ptr - 1) == 'C' || *(ptr - 1) == 'D') {
  1729.                         column = adjustColumn(column, *(ptr - 1) == 'C');
  1730.                         if (column < maxColumn)
  1731.                             goto CHAR_RETRY;
  1732.                     }
  1733.                     continue;
  1734.                 }
  1735.             } else if (c == '\b') {
  1736.                 *ptr++ = c;
  1737.                 column--;
  1738.                 if (column < maxColumn)
  1739.                     goto CHAR_RETRY;
  1740.                 continue;
  1741.             } else if (c == ctrlChr && *ptr2 == *(ptr2 + 1) && strchr("<=>", *ptr2) != NULL) {
  1742.                 goto CTRL_RETRY;
  1743.             } else if (c < '\x20' && c != '\f' || c == '\x7f') {
  1744.                 continue;
  1745.             }
  1746.             ptr2--;
  1747.             break;
  1748.         }
  1749.         if (!WrapFlag) {
  1750.             ptr2 = nextLine(ptr2);
  1751.             bolFlag = TRUE;
  1752.         }
  1753.         if (FillMode < 0) {
  1754.             while (*ptr2 == ' ')
  1755.                 ptr2++;
  1756.             if (*ptr2 == (uchar)(L' ' >> 8) && *(ptr2 + 1) == (uchar)(L' '))
  1757.                 ptr2 += 2;
  1758.         }
  1759.  
  1760. ENCOUNT_EOL:
  1761.         if (alignPtr >= *tlhp) {
  1762.             column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
  1763.             ptr = PTR;
  1764.             alignPtr = NULL;
  1765.         }
  1766.         if (cutAlignMode != 0) {
  1767.             ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
  1768.             if (++cutLineNo >= cutLineNoMax) {
  1769.                 cutNo = -1;
  1770.                 cutAlignMode = 0;
  1771.             }
  1772.         }
  1773.         *ptr++ = '\0';
  1774. ENCOUNT_EOL0:
  1775.  
  1776.         /*
  1777.             CUT '?' フラグの処理
  1778.         */
  1779.         if (cutNo >= 0 && (cut[cutNo].flag & cutDUP)) {
  1780.             int n;
  1781.  
  1782.             cut[cutNo].flag &= ~cutDUP;
  1783.             if ((n = dinstr(*tlhp, cutID)) > 0) {
  1784.                 n += 4 - 1;
  1785.                 while (cutLineNo < cutLineNoMax) {
  1786.                     uchar *p = *tlhp;
  1787.  
  1788.                     *--tlhp = ptr;
  1789.                     if ((void *)ptr > (void *)tlhp)
  1790.                         goto ERROR;
  1791.                     while (*ptr++ = *p++)
  1792.                         ;
  1793.                     *(*tlhp + n) = cutLineNo++;
  1794.                 }
  1795.             }
  1796.             cutNo = -1;
  1797.         }
  1798.  
  1799.         if ((*ptr2 == '\0' || *ptr2 == '\x1a') && tsp->text == NULL)
  1800.             break;
  1801.  
  1802.         if (fontSize > 0 && EolChr != '\n')
  1803.             lineSpace++;
  1804.         while (--lineSpace >= 0) {
  1805.             if (cutAlignMode != 0) {
  1806.                 *--tlhp = ptr;
  1807.                 if (boxStr[0] != '\0')
  1808.                     ptr = stpcpy(ptr, boxStr);
  1809.                 ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
  1810.                 if (++cutLineNo >= cutLineNoMax) {
  1811.                     if (Lspace > 0)
  1812.                         cutBottomSpace = cutAlignMode;
  1813.                     cutNo = -1;
  1814.                     cutAlignMode = 0;
  1815.                 }
  1816.                 *ptr++ = '\0';
  1817.             } else {
  1818.                 if (boxStr[0] != '\0') {
  1819.                     *--tlhp = ptr;
  1820.                     ptr = stpcpy(ptr, boxStr);
  1821.                     *ptr++ = '\0';
  1822.                 } else {
  1823.                     *--tlhp = ptr - 1;
  1824.                 }
  1825.                 tempIndent = -128;
  1826.                 cutBottomSpace = 0;
  1827.             }
  1828.             if ((void *)ptr > (void *)tlhp)
  1829.                 goto ERROR;
  1830.         }
  1831. CHK_TAIL:
  1832.         if (EolChr != '\n')
  1833.             ptr2 = skipNulLine(ptr2);
  1834.         if (fontSize != 0 && *ptr2 == CloseChr) {
  1835.             fontSize = 0;
  1836.             ptr2++;
  1837.             goto CHK_TAIL;
  1838.         }
  1839.     }
  1840.     /*
  1841.     !    一番でかいループおわり
  1842.     */
  1843.  
  1844. ENCOUNT_EOF:
  1845.     if ((void *)ptr > (void *)tlhp) {
  1846.         goto ERROR;    /* 行ポインタテーブルをつぶしてしまった… */
  1847.     } else {
  1848.         int nLine;
  1849.  
  1850.         while (cutAlignMode != 0) {
  1851.             *--tlhp = ptr;
  1852.             if ((void *)ptr > (void *)tlhp)
  1853.                 goto ERROR;
  1854.             ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
  1855.             if (++cutLineNo >= cutLineNoMax) {
  1856.                 cutNo = -1;
  1857.                 cutAlignMode = 0;
  1858.             }
  1859.             *ptr++ = '\0';
  1860.         }
  1861.  
  1862.         /*
  1863.             0行、または、24ドット文字行で終わるファイルは空行を補う
  1864.         */
  1865.         nLine = LINENO;
  1866.         if (nLine == 0 || dinstr(*tlhp, LARGE_IDSTR) > 0) {
  1867.             *--tlhp = ptr;
  1868.             *ptr++ = '\0';
  1869.             nLine++;
  1870.             if ((void *)ptr > (void *)tlhp)
  1871.                 goto ERROR;
  1872.         }
  1873.         lpmx = nLine;
  1874.         lhp = (uchar **)(((int)ptr + 3) & -4);
  1875.  
  1876.         /*
  1877.             行ポインタテーブルを移動し、その末尾アドレスを返す
  1878.         */
  1879.         lhp0 = moveLhp(lhp, tlhp, nLine);
  1880.  
  1881.         goto RETURN;
  1882.     }
  1883.  
  1884. HEAP_ERROR:
  1885.     d_heap();
  1886.  
  1887. ERROR:
  1888.     w_open();
  1889.     w_mes(0, "テキストの展開に失敗しました");
  1890.     w_wait(0);
  1891.     lhp0 = NULL;
  1892.  
  1893. RETURN:
  1894.     while (f->last != NULL) {
  1895.         FORM *ff = f->last;
  1896.         free(f);
  1897.         f = ff;
  1898.     }
  1899.     while (macroListHead != NULL) {
  1900.         MACRO *mp = macroListHead;
  1901.         macroListHead = mp->next;
  1902.         free(mp);
  1903.     }
  1904.     if (kinsokuChrs != defKinsokuChrs)
  1905.         free(kinsokuChrs);
  1906.     while (varListHead != NULL) {
  1907.         VAR *vp = varListHead;
  1908.         varListHead = vp->next;
  1909.         free(vp->contents);
  1910.         free(vp);
  1911.     }
  1912.     while (macroArgs != NULL)
  1913.         freeMacroArg();
  1914.  
  1915.     return lhp0;
  1916. }
  1917.  
  1918.  
  1919. /*
  1920.     24ドット処理の文字列の表示幅調整
  1921.     
  1922.     ptr        調整後のポインタ
  1923.     ptr2        調整するポインタ
  1924.     column        現在桁
  1925.     maxColumn    画面桁幅
  1926.     cont_flag    処理中に最大桁を越えたらTRUE (次行も24ドット表示)
  1927.     
  1928.     戻り値        更新後のcolumn
  1929. */
  1930. static int 
  1931. sort_job24(uchar *ptr, uchar *ptr2, short column, short maxColumn, const FORM *f, uchar *contFlag)
  1932. {
  1933.     if (*ptr2 == CloseChr) {
  1934.         PTR = ptr;
  1935.         PTR2 = ++ptr2;
  1936.         return column;
  1937.     }
  1938.     *ptr++ = CTRL_CHAR;
  1939.     *ptr++ = LARGE_CHAR;
  1940.     *ptr++ = column + NUM_BIAS;
  1941.     *ptr++ = (curColor & 3) + NUM_BIAS;
  1942.     maxColumn = (maxColumn + maxColumn) - 3;
  1943.     column += column;    // 4ドット単位
  1944.  
  1945.     column = sort_job_12_24(ptr, ptr2, column, maxColumn, f, contFlag, FALSE, CloseChr2);
  1946.     return (column + 2 - 1) >> 1;
  1947. }
  1948.  
  1949.  
  1950. /*
  1951.     12ドット処理の文字列の表示幅調整
  1952. */
  1953. static int 
  1954. sort_job12(uchar *ptr, uchar *ptr2, short column, short maxColumn, const FORM *f, uchar *contFlag)
  1955. {
  1956.     if (*ptr2 == CloseChr) {
  1957.         PTR = ptr;
  1958.         PTR2 = ++ptr2;
  1959.         return column;
  1960.     }
  1961.     *ptr++ = CTRL_CHAR;
  1962.     *ptr++ = SMALL_CHAR;
  1963.     maxColumn = (maxColumn << 2) - 3;
  1964.     column <<= 2;    // 2ドット単位
  1965.  
  1966.     column = sort_job_12_24(ptr, ptr2, column, maxColumn, f, contFlag, TRUE, '\0');
  1967.     return (column + 4 - 1) >> 2;
  1968. }
  1969.  
  1970.  
  1971. /*
  1972.     12/24 ドット処理本体
  1973. */
  1974. static int 
  1975. sort_job_12_24(uchar *ptr, uchar *ptr2, short column, short maxColumn,
  1976.     const FORM *f, uchar *contFlag, uchar kinsokuFlag, uchar closeChr2)
  1977. {
  1978.     uchar c, c2;
  1979.     uchar refChr;
  1980.  
  1981.     refChr = RefChr;
  1982.     if (tsp->flag < 0)
  1983.         refChr = '\0';
  1984.     for (;;) {
  1985.         c = *ptr2++;
  1986. retry:
  1987.         if (c == '\0' || c == '\x1a') {
  1988.             if (tsp->text != NULL) {
  1989.                 if (tsp->flag & inMACRO)
  1990.                     freeMacroArg();
  1991.                 ptr2 = tsp->text;
  1992.                 tsp++;
  1993.                 refChr = RefChr;
  1994.                 continue;
  1995.             }
  1996.             break;
  1997.         }
  1998.         if (c == EolChr || c == CloseChr || c == closeChr2)
  1999.             break;
  2000.         if (c == '\t') {
  2001.             short n;
  2002.             if (column > maxColumn) {
  2003.                 ptr2--;
  2004.                 break;
  2005.             }
  2006.             n = column;
  2007.             column += TabWidth * 3;
  2008.             column -= (column % (TabWidth * 3));
  2009.             for (n = (column - n) / 3; --n >= 0;)
  2010.                 *ptr++ = ' ';
  2011.             continue;
  2012.         } else if (c == '\x1b') {
  2013.             int n  = isEscSeq(ptr2);
  2014.             if (n > 0 && *(ptr2 + n - 1) == 'm') {
  2015.                 *ptr++ = c; // ESC
  2016.                 while (--n >= 0)
  2017.                     *ptr++ = *ptr2++;
  2018.                 continue;
  2019.             }
  2020.         } else if (c == EscChr) {
  2021.             c = getEscSeq(ptr2);
  2022.             ptr2 = PTR2;
  2023.             if (iscntrl(c))
  2024.                 goto retry;
  2025.         } else if (iscntrl(c)) {
  2026.             continue;
  2027.         } else if (c == refChr && tsp > textStack + 1) {
  2028.             c = refVar(ptr2, f);
  2029.             ptr2 = PTR2;
  2030.             if (c == 0) {
  2031.                 refChr = '\0';
  2032.                 continue;
  2033.             }
  2034.         }
  2035.         if (column > maxColumn) {
  2036.             ptr2--;
  2037.             break;
  2038.         }
  2039.         if (iskanji1(c)) {
  2040.             c2 = *ptr2++;
  2041.             if (c2 == '\0')
  2042.                 continue;
  2043.             if (iskanji(c)) {
  2044.                 if (column > maxColumn - 3) {
  2045.                     ptr2 -= 2;
  2046.                     break;
  2047.                 }
  2048.                 column += 6;
  2049.             } else {
  2050.                 column += 3;
  2051.             }
  2052.             *ptr++ = c;
  2053.             *ptr++ = c2;
  2054.         } else {
  2055.             *ptr++ = c;
  2056.             column += 3;
  2057.         }    
  2058.     }
  2059.     if (c == '\0' || c == '\x1a' || c == closeChr2)
  2060.         ptr2--;
  2061.     else if (c != CloseChr) {
  2062.         *contFlag = TRUE;
  2063.         if (c == EolChr) {
  2064.             (*contFlag)++;
  2065.         } else if (!WrapFlag) {
  2066.             static uchar term[] = "\x18\n\x1a";
  2067.             (*contFlag)++;
  2068.             term[0] = CloseChr;
  2069.             ptr2 += strcspn(ptr2, term);
  2070.             if (*ptr2 == CloseChr) {
  2071.                 *contFlag = FALSE;
  2072.                 ptr2 += strcspn(ptr2, term + 1);
  2073.             }
  2074.         } else if (kinsokuFlag && iskanji(*ptr2)) {
  2075.             Kinw[0] = ptr2[0];
  2076.             Kinw[1] = ptr2[1];
  2077.             if (dinstr(kinsokuChrs, Kinw)) {
  2078.                 *ptr++ = *ptr2++;
  2079.                 *ptr++ = *ptr2++;
  2080.                 column += 6;
  2081.                 if (*ptr2 == CloseChr) {
  2082.                     *contFlag = FALSE;
  2083.                     ptr2++;
  2084.                 }
  2085.             }
  2086.         }
  2087.     }
  2088.  
  2089.     *ptr++ = NORM_CHAR;
  2090.     PTR = ptr;
  2091.     PTR2 = ptr2;
  2092.  
  2093.     return column;
  2094. }
  2095.  
  2096.  
  2097. /*
  2098.     逆順に生成した行ポインタテーブルを正順に並べ替えつつ移動する
  2099.     どさくさに sort() の後始末
  2100. */
  2101. static uchar **
  2102. moveLhp(uchar **lhp, uchar **tlhp, int n)
  2103. {
  2104.     uchar **p, **q, *t;
  2105.  
  2106.     /*
  2107.         その場で正順に並べ替える
  2108.     */
  2109.     p = tlhp;
  2110.     q = p + n;
  2111.     while (p < q) {
  2112.         t = *--q;
  2113.         *q = *p;
  2114.         *p++ = t;
  2115.     }
  2116.     /*
  2117.         整理済みテキスト直後に移動する
  2118.         ついでに、'◎' の内部コードが残っていたら、対になる 'TYPE=' がないので元に戻す
  2119.     */
  2120.     while (--n >= 0) {
  2121.         *lhp++ = t = *tlhp++;
  2122.         if (*t++ == CTRL_CHAR && *t == DUMMY_CHAR) {
  2123.             *t = (uchar)(L'◎');
  2124.             *--t = (uchar)(L'◎' >> 8);
  2125.         }
  2126.     }
  2127.  
  2128.     return lhp;
  2129. }
  2130.  
  2131.  
  2132. /*
  2133.     'TYPE=' 以降を簡易処理 (コントロールコード類の削除) して
  2134.     作業バッファにコピーしつつ、その画面上での桁幅を返す
  2135. */
  2136. static int
  2137. getTypeLine(uchar *buff, uchar *p, uchar *bound, const FORM *f)
  2138. {
  2139.     int n = 0, m;
  2140.     uchar *q = buff;
  2141.     uchar c;
  2142.  
  2143.     while ((c = *p++) != '\0' && c != '\n' && c != '\x1a') {
  2144.         if (c == '\x1b' && (m = isEscSeq(p))) {
  2145.             n += m + 1;
  2146.             *q++ = c;
  2147.             while (--m >= 0)
  2148.                 *q++ = *p++;
  2149.         }
  2150.         if (iscntrl(c))
  2151.             continue;
  2152.         if (c == RefChr) {
  2153.             if (q + 256 > bound)
  2154.                 return -1;
  2155.             q = envSubst(q, p, f);    // 本当はこの中の2バイト半角も真面目に数えるべきだが省略
  2156.             p = PTR2;
  2157.             continue;
  2158.         }
  2159.         *q++ = c;
  2160.         if (iskanji1(c)) {
  2161.             *q++ = *p++;
  2162.             if (!iskanji(c))
  2163.                 n++;
  2164.         }
  2165.     }
  2166.     *q = '\0';
  2167.     if (c != '\n')
  2168.         p--;
  2169.     PTR2 = p;
  2170.  
  2171.     return (q - buff) - n;
  2172. }
  2173.  
  2174.  
  2175. /*
  2176.     %menu~%endmenu 内のメニュー行の処理
  2177. */
  2178. static int
  2179. getMenuLine(uchar *buff, uchar *p, uchar *bound, const FORM *f)
  2180. {
  2181.     uchar *q = buff;
  2182.     uchar c;
  2183.     int n;
  2184.  
  2185.     *q++ = FALSE;    // 仮に実行可能フラグ OFF
  2186.     while ((c = *p++) != '\0' && c != '\n' && c != '\x1a') {
  2187.         if (iscntrl(c))
  2188.             continue;
  2189.         if (c == RefChr) {
  2190.             if (q + 256 > bound)
  2191.                 return -1;
  2192.             q = envSubst(q, p, f);
  2193.             p = PTR2;
  2194.             continue;
  2195.         }
  2196.         *q++ = c;
  2197.         if (iskanji1(c))
  2198.             *q++ = *p++;
  2199.     }
  2200.     *q++ = '\0';
  2201.     if (c != '\n')
  2202.         p--;
  2203.     PTR2 = p;
  2204.     n = dinstr(buff + 1, "TYPE=");
  2205.     if (n > 0) {
  2206.         *buff = TRUE;
  2207.         q = buff + n;
  2208.         p = q + 5;
  2209.         // メニュー項目文字列とTYPE=の間の空白を削る (0x8020 なんかがあるとコケる)
  2210.         while (--q >= buff + 1 && (*q == ' ' || *q == '\t'))
  2211.             ;
  2212.         q++;
  2213.         *q++ = '\0';
  2214.         while ((*q++ = *p++) != '\0')
  2215.             ;
  2216.     }
  2217.  
  2218.     PTR = q;
  2219.     return 0;
  2220. }
  2221.  
  2222.  
  2223. /*
  2224.     シェル変数/環境変数内容の取得
  2225. */
  2226. static uchar *
  2227. getSysVar(uchar *name)
  2228. {
  2229.     SHELLVAR *vp;
  2230.     uchar *p = NULL;
  2231.  
  2232.     for (vp = sysVarListHead; vp != NULL; vp = vp->next) {
  2233.         if (strEqu(name, vp->name)) {
  2234.             p = vp->name;
  2235.             while (*p++)
  2236.                 ;
  2237.             break;
  2238.         }
  2239.     }
  2240.     if (vp == NULL)
  2241.         p = getenv(name);
  2242.     return p;
  2243. }
  2244.  
  2245. static uchar *
  2246. copySysVar(uchar *name, uchar *buff)
  2247. {
  2248.     VAR *vp;
  2249.     uchar *p;
  2250.  
  2251.     vp = getVar(name);
  2252.     if (vp == NULL)
  2253.         return buff;
  2254.  
  2255.     p = vp->contents;
  2256.     while (*buff++ = *p++)
  2257.         ;
  2258.     return --buff;
  2259. }
  2260.  
  2261.  
  2262. /*
  2263.     TYPE=~ 中の変数置換
  2264. */
  2265. static uchar *
  2266. envSubst(uchar *p, uchar *name, const FORM *f)
  2267. {
  2268.     uchar *q, c;
  2269.  
  2270.     PTR2 = q = name;
  2271.     while ((c = *q++) != '\0' && c != CloseChr && c > '\x20') {
  2272.         if (iskanji1(c))
  2273.             q++;
  2274.     }
  2275.     if (c != CloseChr || q - name >= 256) {
  2276.         *p++ = RefChr;
  2277.     } else {
  2278.         if (q - name > 1) {
  2279.             *(q - 1) = '\0';
  2280.             p = copySysVar(name, p);
  2281.             *(q - 1) = c;
  2282.         } else {
  2283.             *p++ = RefChr;
  2284.         }
  2285.         PTR2 = q;
  2286.     }
  2287.     return p;
  2288. }
  2289.  
  2290.  
  2291. /*
  2292.     右詰めとセンタリング (先頭桁位置の調整)
  2293. */
  2294. static int
  2295. align(uchar *tail, uchar *p, short column, short lmargin, uchar alignMode)
  2296. {
  2297.     short d;
  2298.     int n;
  2299.  
  2300.     *tail = '\0';
  2301.     PTR = tail;
  2302.     if (tail == p) {
  2303.         strcpy(p - 5, p);    // ESC[00C を削除
  2304.         PTR -= 5;
  2305.         return 0;
  2306.     }
  2307.     column -= lmargin;
  2308.     if (alignMode == '=')
  2309.         column /= 2;
  2310.     column += lmargin;
  2311.     if (column < 0)
  2312.         column = 0;
  2313.     --p;
  2314.     d = *--p - '0';
  2315.     d += (*--p - '0') * 10;
  2316.     d = column - d;
  2317.     if (column == 0) {
  2318.         p -= 2;
  2319.         strcpy(p, p + 5);    // ESC[00C を削除
  2320.         PTR -= 5;
  2321.     } else {
  2322.         *p++ = (column / 10) + '0';
  2323.         *p++ = (column % 10) + '0';
  2324.     }
  2325.     while (n = dinstrchr(p, CTRL_CHAR)) {
  2326.         p += n;
  2327.         switch (*p) {
  2328.         case LARGE_CHAR:
  2329.             *(p + 1) += d;
  2330.             break;
  2331.         case CUT_CHAR:
  2332.             *(p + 4) += d;
  2333.             break;
  2334.         }
  2335.     }
  2336.     return d;
  2337. }
  2338.  
  2339.  
  2340. /*
  2341.     ESC[~C, ESC[~D 後のカラム位置調整
  2342. */
  2343. static short
  2344. adjustColumn(short column, uchar forwardFlag)
  2345. {
  2346.     int n;
  2347.     extern uchar escNumBuff[];
  2348.  
  2349.     n = atoi(escNumBuff);
  2350.     if (n == 0)
  2351.         n++;
  2352.     if (forwardFlag)
  2353.         column += n;
  2354.     else if (column >= n)
  2355.         column -= n;
  2356.     else
  2357.         column = 0;
  2358.  
  2359.     return column;
  2360. }
  2361.  
  2362.  
  2363. /*
  2364.     インデント付け用桁送り文字列を得る
  2365. */
  2366. static uchar *
  2367. getIndentStr(uchar *p, short n)
  2368. {
  2369.     const uchar *indentStrTable[] = {
  2370.         "", "\f", "\f\f", "\f\f\f", "\f\f\f\f", "\t\b\b\b", "\t\b\b", "\t\b", "\t",
  2371.     };
  2372.  
  2373.     if (n <= 8)
  2374.         p = stpcpy(p, indentStrTable[n]);
  2375.     else if (n == 16)
  2376.         p = stpcpy(p, "\t\t");
  2377.     else if (n == 24)
  2378.         p = stpcpy(p, "\t\t\t");
  2379.     else
  2380.         p += sprintf(p, "\x1b[%dC", n);
  2381.     return p;
  2382. }
  2383.  
  2384.  
  2385. /*
  2386.     引用表現された文字の取得
  2387. */
  2388. static uchar
  2389. getEscSeq(uchar *p)
  2390. {
  2391.     uchar c;
  2392.  
  2393.     while ((c = *p++) == '\r')
  2394.         ;
  2395.     switch (c) {
  2396.     case '\0':
  2397.         PTR2 = p - 1;
  2398.         return c;
  2399.     case 'a':
  2400.         c = '\a'; break;
  2401.     case 'b':
  2402.         c = '\b'; break;
  2403.     case 'e':
  2404.         c = '\x1b'; break;
  2405.     case 'f':
  2406.         c = '\f'; break;
  2407.     case 'n':
  2408.         c = '\n'; break;
  2409.     case 'r':
  2410.         c = '\r'; break;
  2411.     case 't':
  2412.         c = '\t'; break;
  2413.     case 'v':
  2414.         c = '\v'; break;
  2415.     case 'x':
  2416.         if (isxdigit(*p) && isxdigit(*(p + 1))) {
  2417.             uchar cc;
  2418.  
  2419.             c = (*p++ | 0x20) - '0';
  2420.             if (c >= 10)
  2421.                 c -= 'a' - '0' - 10;
  2422.             cc = (*p++ | 0x20) - '0';
  2423.             if (cc >= 10)
  2424.                 cc -= 'a' - '0' - 10;
  2425.             c = (c << 4) + cc;
  2426.         }
  2427.         break;
  2428.     case '0':
  2429.     case '1':
  2430.         if (isodigit(*p) && isodigit(*(p + 1))) {
  2431.             c = c - '0';
  2432.             c = (c << 3) | (*p++ - '0');
  2433.             c = (c << 3) | (*p++ - '0');
  2434.         }
  2435.         break;
  2436.     }
  2437.  
  2438.     PTR2 = p;
  2439.     return c;
  2440. }
  2441.  
  2442.  
  2443. /*
  2444.     書式指定コマンド番号の取得
  2445. */
  2446. static int
  2447. getCommand(uchar *p, uchar headFlag)
  2448. {
  2449.     int i;
  2450.  
  2451.     PTR2 = p;
  2452.     for (i = 1; i < NCMDS; i++) {
  2453.         int n;
  2454.  
  2455.         if (version < commandTable[i].version)
  2456.             continue;
  2457.         n = strlen(commandTable[i].name);
  2458.         if (strnEqu(p, commandTable[i].name, n) && p[n] <= '\x20') {
  2459.             uchar c;
  2460.  
  2461.             if (!headFlag && (commandTable[i].flag & cfBREAK)) {
  2462.                 PTR2--;
  2463.                 return RETRY_CMD;
  2464.             }
  2465.             p += n;
  2466.             while ((c = *p++) == ' ' || c == '\t' || c == '\r')
  2467.                 ;
  2468.             PTR2 = --p;
  2469.             return i;
  2470.         }
  2471.     }
  2472.     return -1;
  2473. }
  2474.  
  2475.  
  2476. /*
  2477.     10進数値を得る
  2478. */
  2479. static short
  2480. getNum(uchar *p, short n)
  2481. {
  2482.     uchar c;
  2483.  
  2484.     p = skipBlank(p);
  2485.     if (*p == '+')
  2486.         n += atoi(++p);
  2487.     else if (*p == '-')
  2488.         n -= atoi(++p);
  2489.     else
  2490.         n = atoi(p);
  2491.     while ((c = *p++) == '+' || c == '-')
  2492.         ;
  2493.     p--;
  2494.     while ((c = *p++) >= '0' && c <= '9')
  2495.         ;
  2496.     PTR2 = --p;
  2497.  
  2498.     return n;
  2499. }
  2500.  
  2501.  
  2502. static short
  2503. getNum2(uchar *p, short n, short defVal, short baseVal)
  2504. {
  2505.     if (*p == '*') {
  2506.         p = skipBlank(p + 1);
  2507.         if ((n = defVal) < 0)
  2508.             n = baseVal;
  2509.         if (*p != '+' && *p != '-') {
  2510.             PTR2 = p;
  2511.             return n;
  2512.         }
  2513.     }
  2514.     return getNum(p, n);
  2515. }
  2516.  
  2517.  
  2518. /*
  2519.     色コードを得る
  2520. */
  2521. static ushort
  2522. getRGB(uchar *p, ushort defColor)
  2523. {
  2524.     p = skipBlank(p);
  2525.     if (*p++ == '(') {
  2526.         uchar c[3];
  2527.         short i;
  2528.         for (i = 0; i < 3; i++) {
  2529.             int n;
  2530.             p = skipBlank(p);
  2531.             if (*p < '0' || *p > '9')
  2532.                 break;
  2533.             n = atoi(p);
  2534.             if (n < 0 || n > 31)
  2535.                 break;
  2536.             c[i] = n;
  2537.             p += strspn(p, "0123456789");
  2538.             p = skipBlank(p);
  2539.             if (i < 2 && *p++ != ',')
  2540.                 break;
  2541.         }
  2542.         if (i == 3 && *p++ == ')')
  2543.             return (c[0] << 6) | (c[1] << 11) | (c[2] << 1);
  2544.     }
  2545.     return defColor;
  2546. }
  2547.  
  2548.  
  2549. /*
  2550.     %h-rule
  2551. */
  2552. static short
  2553. getHRuleChar(uchar *buff, uchar **pp)
  2554. {
  2555.     uchar *p = *pp;
  2556.     uchar c;
  2557.     short n = 1;
  2558.  
  2559.     c = *p++;
  2560.     buff[0] = c;
  2561.     buff[1] = '\0';
  2562.     if (iskanji1(c)) {
  2563.         buff[1] = *p++;
  2564.         if (iskanji(c))
  2565.             n++;
  2566.     }
  2567.     *pp = p;
  2568.     return n;
  2569. }
  2570.  
  2571. static uchar *
  2572. getHRule(uchar *p, uchar *p2, short n)
  2573. {
  2574.     uchar ch1[2], ch2[2], ch3[2];
  2575.     short l1, l2, l3;
  2576.  
  2577.     if (n <= 0)
  2578.         return p;
  2579.     if (iscntrl(*p2) || *p2 == ' ') {
  2580.         ch1[0] = (uchar)(L'━' >> 8);
  2581.         ch1[1] = (uchar)(L'━');
  2582.         l1 = 2;
  2583.     } else
  2584.         l1 = getHRuleChar(ch1, &p2);
  2585.     if (l1 > n)
  2586.         return p;
  2587.     if (iscntrl(*p2)) {
  2588.         ch2[0] = ch1[0];
  2589.         ch2[1] = ch1[1];
  2590.         ch3[0] = ch1[0];
  2591.         ch3[1] = ch1[1];
  2592.         l2 = l3 = l1;
  2593.     } else {
  2594.         l2 = getHRuleChar(ch2, &p2);
  2595.         if (iscntrl(*p2))
  2596.             l3 = 0;
  2597.         else
  2598.             l3 = getHRuleChar(ch3, &p2);
  2599.     }
  2600.     if (l3 == 0) {
  2601.         while (n >= l1) {
  2602.             *p++ = ch1[0];
  2603.             if ((*p++ = ch1[1]) == '\0')
  2604.                 p--;
  2605.             n -= l1 + l2;
  2606.             if (n < 0)
  2607.                 break;
  2608.             *p++ = ch2[0];
  2609.             if ((*p++ = ch2[1]) == '\0')
  2610.                 p--;
  2611.         }
  2612.     } else {
  2613.         *p++ = ch1[0];
  2614.         if ((*p++ = ch1[1]) == '\0')
  2615.             p--;
  2616.         n -= l1;
  2617.         while (n >= l2 + l3) {
  2618.             *p++ = ch2[0];
  2619.             if ((*p++ = ch2[1]) == '\0')
  2620.                 p--;
  2621.             n -= l2;
  2622.         }
  2623.         *p++ = ch3[0];
  2624.         if ((*p++ = ch3[1]) == '\0')
  2625.             p--;
  2626.     }
  2627.  
  2628.     return p;
  2629. }
  2630.  
  2631. /*
  2632.     マクロの定義内容を得る
  2633. */
  2634. static uchar *
  2635. getMacro(MACRO *mp, uchar *p, uchar closeChr)
  2636. {
  2637.     PTR2 = p;
  2638.     while (mp != NULL) {
  2639.         int n = strlen(mp->name);
  2640.         if (strnEqu(p, mp->name, n) && (p[n] <= 0x20 || p[n] == closeChr || p[n] == '(')) {
  2641.             PTR2 = p + n;
  2642.             return mp->contents;
  2643.         }
  2644.         mp = mp->next;
  2645.     }
  2646.  
  2647.     return NULL;
  2648. }
  2649.  
  2650.  
  2651. static int
  2652. setSysVar(const uchar *name, const uchar *contents)
  2653. {
  2654.     SHELLVAR *vp;
  2655.     int n = strlen(name) + 1;
  2656.     
  2657.     vp = malloc(sizeof(SHELLVAR) + n + strlen(contents) + 1);
  2658.     if (vp == NULL)
  2659.         return -1;
  2660.     strcpy(vp->name, name);
  2661.     strcpy(vp->name + n, contents);
  2662.     vp->next = sysVarListHead;
  2663.     sysVarListHead = vp;
  2664.  
  2665.     return 0;
  2666. }
  2667.  
  2668.  
  2669. /*
  2670.     変数の定義内容を得る
  2671. */
  2672. static VAR *
  2673. getVar(const uchar *name)
  2674. {
  2675.     VAR *vp;
  2676.     uchar *p;
  2677.  
  2678.     if (*(name + 1) == '\0' && isdigit(*name)) {
  2679.         if (macroArgs == NULL)
  2680.             return NULL;
  2681.         else
  2682.             return macroArgs->arg[*name - '0'];
  2683.     }
  2684.     for (vp = varListHead; vp != NULL; vp = vp->next) {
  2685.         if (strEqu(name, vp->name))
  2686.             return vp;
  2687.     }
  2688.     p = getSysVar(name);
  2689.     if (p != NULL && (p = strdup(p)) != NULL) {
  2690.         vp = malloc(sizeof(VAR) + strlen(name) + 1);
  2691.         vp->contents = p;
  2692.         strcpy(vp->name, name);
  2693.         vp->next = varListHead;
  2694.         varListHead = vp;
  2695.         return vp;
  2696.     }
  2697.     return NULL;
  2698. }
  2699.  
  2700. static int
  2701. setVar(const uchar *name, const uchar *contents)
  2702. {
  2703.     VAR *vp;
  2704.  
  2705.     vp = getVar(name);
  2706.     if (vp == NULL) {
  2707.         vp = malloc(sizeof(VAR) + strlen(name) + 1);
  2708.         strcpy(vp->name, name);
  2709.         vp->next = varListHead;
  2710.         varListHead = vp;
  2711.     } else {
  2712.         free(vp->contents);
  2713.     }
  2714.     vp->contents = strdup(contents);
  2715.     if (vp->contents == NULL)
  2716.         return -1;
  2717.  
  2718.     return 0;
  2719. }
  2720.  
  2721. static int
  2722. incVar(const uchar *name)
  2723. {
  2724.     static const ushort rangeTable[][3] = {
  2725.         { '0', '1', '9', },
  2726.         { 'A', 'A', 'Z', },
  2727.         { 'a', 'a', 'z', },
  2728.         { L'0', L'1', L'9', },
  2729.         { L'A', L'A', L'Z', },
  2730.         { L'a', L'a', L'z', },
  2731.         { L'Α', L'Α', L'Ω', },
  2732.         { L'α', L'α', L'ω', },
  2733.     };
  2734.     static const uchar zenHira[] =
  2735.         "あいうえおかきくけこさしすせそたちつてとなにぬねの"
  2736.         "はひふへほまみむめもやゆよらりるれろわをん";
  2737.     static const uchar zenKata[] =
  2738.         "アイウエオカキクケコサシスセソタチツテトナニヌネノ"
  2739.         "ハヒフヘホマミムメモヤユヨラリルレロワヲン";
  2740.     static const uchar hanKata[] =
  2741.         "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン";
  2742.     VAR *vp;
  2743.     uchar c, *p;
  2744.     ushort lastChr;
  2745.     short n;
  2746.  
  2747.     vp = getVar(name);
  2748.     if (vp == NULL) {
  2749.         if ((vp = malloc(sizeof(VAR) + strlen(name) + 1)) == NULL)
  2750.             return -1;
  2751.         strcpy(vp->name, name);
  2752.         vp->next = varListHead;
  2753.         varListHead = vp;
  2754.         if ((vp->contents = strdup("1")) == NULL)
  2755.             return -1;
  2756.         return 0;
  2757.     }
  2758.  
  2759.     lastChr = '\0';
  2760.     p = vp->contents;
  2761.     while ((c = *p++) != '\0') {
  2762.         if (iskanji1(c))
  2763.             lastChr = (c << 8) | *p++;
  2764.         else
  2765.             lastChr = c;
  2766.     }
  2767.     p--;
  2768.  
  2769. #define    head    (rangeTable[n][0])
  2770. #define    head2    (rangeTable[n][1])
  2771. #define    tail    (rangeTable[n][2])
  2772.     for (n = 0; n < sizeof(rangeTable) / sizeof(rangeTable[0]); n++) {
  2773.         if (lastChr >= head && lastChr <= tail)
  2774.             break;
  2775.     }
  2776.     if (n >= sizeof(rangeTable) / sizeof(rangeTable[0])) {
  2777.         if (lastChr < 0x0100) {
  2778.             if ((n = dinstrchr(hanKata, *--p)) > 0) {
  2779.                 if (hanKata[n] != '\0')
  2780.                     *p = hanKata[n];
  2781.             }
  2782.         } else {
  2783.             uchar *q;
  2784.             p -= 2;
  2785.             if ((n = dinstr(q = zenHira, p)) > 0
  2786.               || (n = dinstr(q = zenKata, p)) > 0) {
  2787.                 q += n + 2 - 1;
  2788.                 if (*q != '\0') {
  2789.                     *p++ = *q++;
  2790.                     *p = *q;
  2791.                 }
  2792.             }
  2793.         }
  2794.         return 0;
  2795.     }
  2796.     if (head < 0x100) {
  2797.         if (++(*--p) <= tail)
  2798.             return 0;
  2799.         *p = head;
  2800.         while (--p >= vp->contents) {
  2801.             if (*p == ' ') {
  2802.                 *p = head2;
  2803.                 return 0;                
  2804.             }
  2805.             if (*p < head || *p > tail)
  2806.                 return 0;                
  2807.             if ((*p)++ <= tail)
  2808.                 return 0;
  2809.         }
  2810.         p = malloc(strlen(vp->contents) + 2);
  2811.         if (p == NULL)
  2812.             return -1;
  2813.         strcpy(p + 1, vp->contents);
  2814.         free(vp->contents);
  2815.         vp->contents = p;
  2816.         *p++ = head2;
  2817.     } else {
  2818.         uchar highByte = (head >> 8);
  2819.         if (++(*--p) <= (uchar)tail)
  2820.             return 0;
  2821.         *p = head;
  2822.         p--;
  2823.         while ((p -= 2) >= vp->contents) {
  2824.             if (*p == ' ' && *(p + 1) == ' '
  2825.               || *p == (uchar)(L' '>>8) && *(p + 1) == (uchar)L' ') {
  2826.                 *p++ = highByte;
  2827.                 *p = head2;
  2828.                 return 0;
  2829.             }
  2830.             if (*p != highByte || *(p + 1) < (uchar)head || *(p + 1) > (uchar)tail)
  2831.                 return 0;                
  2832.             if ((*(p + 1))++ <= (uchar)tail)
  2833.                 return 0;
  2834.         }
  2835.         if (p + 2 != vp->contents)
  2836.             return 0;
  2837.         p = malloc(strlen(vp->contents) + 3);
  2838.         if (p == NULL)
  2839.             return -1;
  2840.         strcpy(p + 2, vp->contents);
  2841.         free(vp->contents);
  2842.         vp->contents = p;
  2843.         *p++ = highByte;
  2844.         *p = head2;
  2845.     }
  2846.     return 0;
  2847. #undef    head
  2848. #undef    head2
  2849. #undef    tail
  2850. }
  2851.  
  2852. static uchar
  2853. refVar(uchar *p, const FORM *f)
  2854. {
  2855.     uchar *name = p, c;
  2856.     VAR *vp;
  2857.  
  2858.     while ((c = *p++) != '\0' && c != CloseChr && c > '\x20')
  2859.         ;
  2860.     if (c != CloseChr) {
  2861.         p = name;
  2862.         c = RefChr;
  2863.     } else {
  2864.         *--p = '\0';
  2865.         vp = getVar(name);
  2866.         *p++ = c;
  2867.         if (EolChr != '\n')
  2868.             p = skipNulLine(p);
  2869.         if (vp != NULL && *vp->contents != '\0') {
  2870.             (--tsp)->text = p;
  2871.             tsp->flag = inCONST;
  2872.             p = vp->contents;
  2873.         }
  2874.         c = '\0';
  2875.     }
  2876.     PTR2 = p;
  2877.     return c;
  2878. }
  2879.  
  2880.  
  2881. static uchar *
  2882. expandCommand(uchar *temp, uchar *q, const FORM *f, uchar argFlag)
  2883. {
  2884.     uchar c;
  2885.     uchar quoteChr = '\0';
  2886.  
  2887.     while ((c = *q++) != '\0' && c != '\r' && c != '\n' && c != '\x1a') {
  2888.         if (c == quoteChr) {
  2889.             quoteChr = '\0';
  2890.             continue;
  2891.         }
  2892.         if (quoteChr == '\0') {
  2893.             if (c == '\'' || c == '\"') {
  2894.                 quoteChr = c;
  2895.                 continue;
  2896.             }
  2897.             if (c == RefChr) {
  2898.                 uchar *qq = q;
  2899.                 VAR *vp;
  2900.  
  2901.                 while ((c = *q++) != '\0' && c != CloseChr && c > '\x20')
  2902.                     ;
  2903.                 *--q = '\0';
  2904.                 vp = getVar(qq);
  2905.                 if ((*q = c) == CloseChr)
  2906.                     q++;
  2907.                 if (vp != NULL) {
  2908.                     for (qq = vp->contents; (*temp++ = *qq++) != '\0';)
  2909.                         ;
  2910.                     temp--;
  2911.                 }
  2912.                 continue;
  2913.             }
  2914.             if (argFlag && (c == ' ' || c == '\t' || c == ',' || c == ')')) {
  2915.                 if (c == ')')
  2916.                     q--;
  2917.                 *temp = '\0';
  2918.                 return q;
  2919.             }
  2920.             if ((argFlag || version >= v3_32) && c == EscChr) {
  2921.                 c = getEscSeq(q);
  2922.                 q = PTR2;
  2923.                 if (iscntrl(c) && c != '\t' && c != '\f' && c != '\b' && c != '\r' && c != '\x1b')
  2924.                     continue;
  2925.             }
  2926.         }
  2927.         if (iskanji1(c)) {
  2928.             *temp++ = c;
  2929.             *temp++ = *q++;
  2930.         } else
  2931.             *temp++ = c;
  2932.     }
  2933.     *temp = '\0';
  2934.  
  2935.     q--;
  2936.     if (!argFlag) {
  2937.         q = nextLine(q);
  2938.         if (EolChr != '\n')
  2939.             q = skipNulLine(q);
  2940.     }
  2941.  
  2942.     return q;
  2943. }
  2944.  
  2945.  
  2946. uchar *
  2947. expandMacroArg(ARGS *ap, uchar *temp, uchar *q, const FORM *f)
  2948. {
  2949.     VAR *vp;
  2950.     int n;
  2951.     uchar c;
  2952.  
  2953.     for (n = 0; n < 10; n++) {
  2954.         while ((c = *q++) == ' ' || c == '\t' || c == '\r')
  2955.             ;
  2956.         if (c == ')')
  2957.             return q;
  2958.         q--;
  2959.         if (c == '\n')
  2960.             return q;
  2961.         q = expandCommand(temp, q, f, TRUE);
  2962.         if ((vp = malloc(sizeof(VAR))) == NULL)
  2963.             return NULL;
  2964.         vp->next = NULL;
  2965.         if ((vp->contents = strdup(temp)) == NULL)
  2966.             return NULL;
  2967.         ap->arg[n] = vp;
  2968.     }
  2969.     while ((c = *q++) == ' ' || c == '\t' || c == '\r')
  2970.         ;
  2971.     if (c == ')')
  2972.         return q;
  2973.     else
  2974.         return --q;
  2975. }
  2976.  
  2977.  
  2978. static void
  2979. freeMacroArg(void)
  2980. {
  2981.     ARGS *ap;
  2982.     VAR *vp;
  2983.     int n;
  2984.  
  2985.     if ((ap = macroArgs) == NULL)
  2986.         return;
  2987.     macroArgs = ap->prev;
  2988.     for (n = 0; n < 10; n++) {
  2989.         if ((vp = ap->arg[n]) == NULL)
  2990.             break;
  2991.         free(vp->contents);
  2992.         free(vp);
  2993.     }
  2994.     free(ap);
  2995. }
  2996.  
  2997. static int
  2998. skipIfBlock(const uchar *p, uchar ctrlChr, uchar elseFlag)
  2999. {
  3000.     for (;;) {
  3001.         if (*p == '\0' || *p == '\x1a')
  3002.             break;
  3003.         if (*p++ == ctrlChr) {
  3004.             switch (getCommand(p, TRUE)) {
  3005.             case IF_CMD:
  3006.                 skipIfBlock(nextLine(p), ctrlChr, FALSE);
  3007.                 p = PTR2;
  3008.                 break;
  3009.             case ELIF_CMD:
  3010.                 if (elseFlag)
  3011.                     return TRUE;
  3012.                 break;
  3013.             case ELSE_CMD:
  3014.                 if (!elseFlag)
  3015.                     break;
  3016.                 /* NOBREAK */
  3017.             case ENDIF_CMD:
  3018.                 PTR2 = nextLine(p);
  3019.                 return FALSE;
  3020.             }
  3021.             p = nextLine(p);
  3022.         }
  3023.     }
  3024.     PTR2 = p;
  3025.  
  3026.     return FALSE;
  3027. }
  3028.  
  3029. static uchar *
  3030. insertCut(uchar *p, short cutNo, uchar cutLineNo, uchar cutColumn, uchar cutColor)
  3031. {
  3032.     if (cutColor != curColor)
  3033.         p = setColor(p, cutColor);
  3034.     *p++ = CTRL_CHAR;
  3035.     *p++ = CUT_CHAR;
  3036.     *p++ = (cutNo >> 6) + NUM_BIAS;
  3037.     *p++ = (cutNo & (64 - 1)) + NUM_BIAS;
  3038.     *p++ = cutLineNo;
  3039.     *p++ = cutColumn + NUM_BIAS;
  3040.  
  3041.     return p;
  3042. }
  3043.  
  3044. static uchar *
  3045. setColor(uchar *p, uchar color)
  3046. {
  3047.     *p++ = '\x1b';
  3048.     *p++ = '[';
  3049.     if (color < 8)
  3050.         *p++ = '3';
  3051.     else
  3052.         *p++ = '4';
  3053.     *p++ = (color & 7) + '0';
  3054.     *p++ = 'm';
  3055.  
  3056.     return p;
  3057. }
  3058.